<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: göktürk kahriman</title>
    <description>The latest articles on Forem by göktürk kahriman (@gktrk_kahriman_192cb6da).</description>
    <link>https://forem.com/gktrk_kahriman_192cb6da</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3868315%2Fe42dc2f0-8666-45ef-b614-be92df587f4d.jpeg</url>
      <title>Forem: göktürk kahriman</title>
      <link>https://forem.com/gktrk_kahriman_192cb6da</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/gktrk_kahriman_192cb6da"/>
    <language>en</language>
    <item>
      <title>Why Most File Tools Still Feel Broken</title>
      <dc:creator>göktürk kahriman</dc:creator>
      <pubDate>Fri, 17 Apr 2026 14:55:10 +0000</pubDate>
      <link>https://forem.com/gktrk_kahriman_192cb6da/why-most-file-tools-still-feel-broken-24c1</link>
      <guid>https://forem.com/gktrk_kahriman_192cb6da/why-most-file-tools-still-feel-broken-24c1</guid>
      <description>&lt;p&gt;*&lt;em&gt;Why Most File Tools Still Feel Broken&lt;br&gt;
*&lt;/em&gt;&lt;br&gt;
Most file tools are technically useful.&lt;/p&gt;

&lt;p&gt;They compress PDFs.&lt;br&gt;
Convert images.&lt;br&gt;
Merge documents.&lt;br&gt;
Resize files.&lt;br&gt;
Extract pages.&lt;br&gt;
Sign forms.&lt;/p&gt;

&lt;p&gt;And yet, a surprising number of them still feel broken.&lt;/p&gt;

&lt;p&gt;Not because the core feature fails.&lt;/p&gt;

&lt;p&gt;But because the experience around the feature is unfinished.&lt;/p&gt;

&lt;p&gt;You upload a file.&lt;br&gt;
You process it.&lt;br&gt;
You download it.&lt;br&gt;
Then you realize you still need to do three more things somewhere else.&lt;/p&gt;

&lt;p&gt;That is the real problem.&lt;/p&gt;

&lt;p&gt;The issue with many online tools is not lack of functionality.&lt;/p&gt;

&lt;p&gt;It is lack of flow.&lt;/p&gt;

&lt;p&gt;*&lt;em&gt;The real problem is not the file&lt;br&gt;
*&lt;/em&gt;&lt;br&gt;
When people search for a file tool, they usually do not care about the tool itself.&lt;/p&gt;

&lt;p&gt;They care about the job they are trying to finish.&lt;/p&gt;

&lt;p&gt;They are not thinking:&lt;/p&gt;

&lt;p&gt;I need a PDF compressor&lt;br&gt;
I need a JPG converter&lt;br&gt;
I need a file merger&lt;/p&gt;

&lt;p&gt;They are thinking:&lt;/p&gt;

&lt;p&gt;I need to send this file&lt;br&gt;
I need this document ready for a client&lt;br&gt;
I need this image prepared for upload&lt;br&gt;
I need this PDF signed and safe&lt;/p&gt;

&lt;p&gt;That difference matters.&lt;/p&gt;

&lt;p&gt;*&lt;em&gt;A feature solves one action.&lt;br&gt;
*&lt;/em&gt;&lt;br&gt;
A good product helps finish the outcome.&lt;/p&gt;

&lt;p&gt;Too many online file tools stop at the feature.&lt;/p&gt;

&lt;p&gt;That is why they still feel broken.&lt;/p&gt;

&lt;p&gt;The upload-download-upload-again problem&lt;/p&gt;

&lt;p&gt;A typical file workflow still looks like this:&lt;/p&gt;

&lt;p&gt;Open one website to compress a PDF&lt;br&gt;
Download the compressed file&lt;br&gt;
Open another website to sign it&lt;br&gt;
Upload the same file again&lt;br&gt;
Download it again&lt;br&gt;
Open another website to protect it&lt;br&gt;
Upload it again&lt;br&gt;
Download the final version&lt;/p&gt;

&lt;p&gt;This flow is common.&lt;/p&gt;

&lt;p&gt;It is also terrible.&lt;/p&gt;

&lt;p&gt;The individual tools may work perfectly.&lt;/p&gt;

&lt;p&gt;But the overall experience is full of friction.&lt;/p&gt;

&lt;p&gt;The user is doing repeated work:&lt;/p&gt;

&lt;p&gt;re-uploading the same file&lt;br&gt;
re-orienting themselves to a new interface&lt;br&gt;
waiting through the same process again&lt;br&gt;
worrying about whether the file still looks right&lt;br&gt;
losing momentum between steps&lt;/p&gt;

&lt;p&gt;That is why file tools often feel more exhausting than they should.&lt;/p&gt;

&lt;p&gt;A tool is not enough if the next step is missing&lt;/p&gt;

&lt;p&gt;This is the mistake I think many founders make.&lt;/p&gt;

&lt;p&gt;They build a feature and assume the job is done.&lt;/p&gt;

&lt;p&gt;But for the user, the result screen is often only the middle of the task.&lt;/p&gt;

&lt;p&gt;A PDF merger should not end at “Download.”&lt;/p&gt;

&lt;p&gt;Because after merging a PDF, the user may still want to:&lt;/p&gt;

&lt;p&gt;compress it&lt;br&gt;
reorder pages&lt;br&gt;
sign it&lt;br&gt;
protect it&lt;br&gt;
open it in an editor&lt;br&gt;
send it professionally&lt;/p&gt;

&lt;p&gt;An image converter should not end at “Download.”&lt;/p&gt;

&lt;p&gt;Because after converting an image, the user may still want to:&lt;/p&gt;

&lt;p&gt;crop it&lt;br&gt;
resize it&lt;br&gt;
compress it&lt;br&gt;
remove the background&lt;br&gt;
export it into a document or PDF&lt;/p&gt;

&lt;p&gt;A document creator should not end at “Export.”&lt;/p&gt;

&lt;p&gt;Because after creating a document, the user may still want to:&lt;/p&gt;

&lt;p&gt;turn it into a PDF&lt;br&gt;
sign it&lt;br&gt;
annotate it&lt;br&gt;
prepare it for sharing&lt;/p&gt;

&lt;p&gt;The next step is not an extra feature.&lt;/p&gt;

&lt;p&gt;The next step is part of the product.&lt;/p&gt;

&lt;p&gt;*&lt;em&gt;Why so many file tools feel disposable&lt;br&gt;
*&lt;/em&gt;&lt;br&gt;
Many online tools are designed like vending machines.&lt;/p&gt;

&lt;p&gt;Input.&lt;br&gt;
Output.&lt;br&gt;
Goodbye.&lt;/p&gt;

&lt;p&gt;That model can generate traffic.&lt;/p&gt;

&lt;p&gt;It can even rank in search.&lt;/p&gt;

&lt;p&gt;But it rarely creates loyalty.&lt;/p&gt;

&lt;p&gt;Users may come once, solve one problem, and never think about the product again.&lt;/p&gt;

&lt;p&gt;That is very different from a system that helps users keep going.&lt;/p&gt;

&lt;p&gt;The products people remember are not always the ones with the longest feature lists.&lt;/p&gt;

&lt;p&gt;They are often the ones that make work feel lighter.&lt;/p&gt;

&lt;p&gt;That is a very different kind of product design goal.&lt;/p&gt;

&lt;p&gt;Better file tools need better workflows&lt;/p&gt;

&lt;p&gt;If online file products want to improve, they need to think beyond individual actions.&lt;/p&gt;

&lt;p&gt;They need to think in workflows.&lt;/p&gt;

&lt;p&gt;A better flow looks like this:&lt;/p&gt;

&lt;p&gt;Open file → fix problem → continue next step → export final result&lt;/p&gt;

&lt;p&gt;That small shift changes everything.&lt;/p&gt;

&lt;p&gt;Instead of asking the user to figure out what to do next, the product starts guiding the experience.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;p&gt;Merge PDF → Compress → Sign → Protect → Download&lt;/p&gt;

&lt;p&gt;Or:&lt;/p&gt;

&lt;p&gt;Image to PDF → Crop → Compress → Export&lt;/p&gt;

&lt;p&gt;Or:&lt;/p&gt;

&lt;p&gt;Create document → Export PDF → Sign → Share&lt;/p&gt;

&lt;p&gt;This is what most file tools are missing.&lt;/p&gt;

&lt;p&gt;Not more features.&lt;/p&gt;

&lt;p&gt;Better continuity.&lt;/p&gt;

&lt;p&gt;The browser is now strong enough for more than quick utilities&lt;/p&gt;

&lt;p&gt;A big reason this matters now is that the browser has become much more capable.&lt;/p&gt;

&lt;p&gt;What used to require heavy desktop software can increasingly happen directly online.&lt;/p&gt;

&lt;p&gt;That includes:&lt;/p&gt;

&lt;p&gt;PDF processing&lt;br&gt;
document editing&lt;br&gt;
image conversion&lt;br&gt;
image cropping&lt;br&gt;
compression&lt;br&gt;
export workflows&lt;br&gt;
signing&lt;br&gt;
annotations&lt;br&gt;
file preparation&lt;/p&gt;

&lt;p&gt;This changes the role of browser-based tools.&lt;/p&gt;

&lt;p&gt;They no longer need to behave like isolated quick fixes.&lt;/p&gt;

&lt;p&gt;They can become connected workspaces.&lt;/p&gt;

&lt;p&gt;That is a much more interesting product category.&lt;/p&gt;

&lt;p&gt;Trust is part of usability&lt;/p&gt;

&lt;p&gt;There is another reason many file tools feel broken.&lt;/p&gt;

&lt;p&gt;They often ignore trust.&lt;/p&gt;

&lt;p&gt;A file is not always just a file.&lt;/p&gt;

&lt;p&gt;It might be:&lt;/p&gt;

&lt;p&gt;a contract&lt;br&gt;
an invoice&lt;br&gt;
a legal document&lt;br&gt;
an assignment&lt;br&gt;
a report&lt;br&gt;
a client deliverable&lt;br&gt;
a sensitive image&lt;/p&gt;

&lt;p&gt;When users work with those kinds of files, they do not only want speed.&lt;/p&gt;

&lt;p&gt;They want confidence.&lt;/p&gt;

&lt;p&gt;A good file product should feel:&lt;/p&gt;

&lt;p&gt;clear&lt;br&gt;
fast&lt;br&gt;
predictable&lt;br&gt;
safe&lt;/p&gt;

&lt;p&gt;That is one of the reasons I am building Kreotar&lt;br&gt;
 the way I am.&lt;/p&gt;

&lt;p&gt;Not as a random list of utilities, but as a browser-based productivity ecosystem for PDFs, documents, images, converters, and connected workflows.&lt;/p&gt;

&lt;p&gt;From isolated tools to connected ecosystems&lt;/p&gt;

&lt;p&gt;This is the shift I find most interesting.&lt;/p&gt;

&lt;p&gt;The future is probably not one massive tool that tries to do everything badly.&lt;/p&gt;

&lt;p&gt;And it is probably not hundreds of isolated utilities either.&lt;/p&gt;

&lt;p&gt;It is connected systems.&lt;/p&gt;

&lt;p&gt;PDF tools that lead into a PDF studio.&lt;br&gt;
Document tools that lead into a document editor.&lt;br&gt;
Image tools that lead into a visual workflow.&lt;br&gt;
Converters that do not force users to restart from zero.&lt;/p&gt;

&lt;p&gt;That is the product direction behind Kreotar.&lt;/p&gt;

&lt;p&gt;A user may arrive to compress a PDF.&lt;/p&gt;

&lt;p&gt;But they should also be able to continue:&lt;/p&gt;

&lt;p&gt;open it in &lt;a href="https://kreotar.com/en/office/kreopdf" rel="noopener noreferrer"&gt;KreoPDF&lt;/a&gt;&lt;br&gt;
sign it&lt;br&gt;
add text&lt;br&gt;
protect it&lt;br&gt;
prepare it for delivery&lt;/p&gt;

&lt;p&gt;That makes the product more useful.&lt;/p&gt;

&lt;p&gt;It also makes the experience feel complete.&lt;/p&gt;

&lt;p&gt;Why this matters for founders&lt;/p&gt;

&lt;p&gt;If you are building online tools, here is the question I think matters most:&lt;/p&gt;

&lt;p&gt;*&lt;em&gt;What happens after the user finishes the first action?&lt;br&gt;
*&lt;/em&gt;&lt;br&gt;
That question is more important than many product teams realize.&lt;/p&gt;

&lt;p&gt;Because if the answer is “they leave and search for another site,” then the product is weaker than it looks.&lt;/p&gt;

&lt;p&gt;The strongest tools are the ones that create momentum.&lt;/p&gt;

&lt;p&gt;The next step should not feel like a new journey.&lt;/p&gt;

&lt;p&gt;It should feel like a continuation.&lt;/p&gt;

&lt;p&gt;That is what turns a tool into a product.&lt;/p&gt;

&lt;p&gt;And over time, it is what turns a product into an ecosystem.&lt;/p&gt;

&lt;p&gt;*&lt;em&gt;Final thought&lt;br&gt;
*&lt;/em&gt;&lt;br&gt;
Most file tools do work.&lt;/p&gt;

&lt;p&gt;But many still feel broken because they stop too early.&lt;/p&gt;

&lt;p&gt;They solve the first action and ignore the rest of the job.&lt;/p&gt;

&lt;p&gt;The next generation of online tools will not win by adding endless features.&lt;/p&gt;

&lt;p&gt;They will win by creating better flows.&lt;/p&gt;

&lt;p&gt;Less re-uploading.&lt;br&gt;
Less friction.&lt;br&gt;
Less confusion.&lt;br&gt;
More continuity.&lt;br&gt;
More finished work.&lt;/p&gt;

&lt;p&gt;That is the direction I am building toward with &lt;a href="https://kreotar.com" rel="noopener noreferrer"&gt;Kreotar&lt;/a&gt;&lt;br&gt;
.&lt;/p&gt;

&lt;p&gt;Not just more tools.&lt;/p&gt;

&lt;p&gt;Better workflows.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>productivity</category>
      <category>startup</category>
      <category>funnel</category>
    </item>
    <item>
      <title>What I Learned Building 260+ Online Tools as a Solo Founder</title>
      <dc:creator>göktürk kahriman</dc:creator>
      <pubDate>Thu, 16 Apr 2026 04:30:57 +0000</pubDate>
      <link>https://forem.com/gktrk_kahriman_192cb6da/what-i-learned-building-260-online-tools-as-a-solo-founder-2m37</link>
      <guid>https://forem.com/gktrk_kahriman_192cb6da/what-i-learned-building-260-online-tools-as-a-solo-founder-2m37</guid>
      <description>&lt;p&gt;Building one tool is already a challenge.&lt;/p&gt;

&lt;p&gt;Building more than 260 online tools as a solo founder teaches you something different.&lt;/p&gt;

&lt;p&gt;It teaches you that the hard part is not only writing code.&lt;/p&gt;

&lt;p&gt;The hard part is creating a system where every tool feels useful, fast, connected, and easy to understand.&lt;/p&gt;

&lt;p&gt;That is what I’m learning while building &lt;a href="https://kreotar.com" rel="noopener noreferrer"&gt;Kreotar&lt;/a&gt;&lt;br&gt;
, a browser-based productivity platform for PDFs, documents, images, converters, and future workflows.&lt;/p&gt;

&lt;p&gt;At first, it may look like a collection of tools.&lt;/p&gt;

&lt;p&gt;*&lt;em&gt;But the deeper goal is bigger:&lt;br&gt;
*&lt;/em&gt;&lt;br&gt;
Build an ecosystem where people can open a file, fix a problem, continue the next step, and finish the work without unnecessary friction.&lt;/p&gt;

&lt;p&gt;*&lt;em&gt;1. More Tools Do Not Automatically Mean More Value&lt;br&gt;
*&lt;/em&gt;&lt;br&gt;
When you build many tools, it is easy to think the value comes from the number.&lt;/p&gt;

&lt;p&gt;100 tools.&lt;br&gt;
200 tools.&lt;br&gt;
260 tools.&lt;/p&gt;

&lt;p&gt;But users do not care about the number.&lt;/p&gt;

&lt;p&gt;They care about whether one tool solves their problem well.&lt;/p&gt;

&lt;p&gt;A PDF merger should merge files clearly.&lt;br&gt;
An image converter should convert without confusion.&lt;br&gt;
A document tool should help create a clean result.&lt;br&gt;
A compressor should make the file smaller without destroying the user experience.&lt;/p&gt;

&lt;p&gt;*&lt;em&gt;The lesson is simple:&lt;br&gt;
*&lt;/em&gt;&lt;br&gt;
A large tool library is only valuable if each tool has a clear purpose.&lt;/p&gt;

&lt;p&gt;Quantity creates reach.&lt;/p&gt;

&lt;p&gt;Quality creates trust.&lt;/p&gt;

&lt;p&gt;*&lt;em&gt;2. The First Screen Matters More Than Most Founders Think&lt;br&gt;
*&lt;/em&gt;&lt;br&gt;
For online tools, the first screen is everything.&lt;/p&gt;

&lt;p&gt;A user should immediately understand:&lt;/p&gt;

&lt;p&gt;What does this tool do?&lt;br&gt;
Where do I upload my file?&lt;br&gt;
Is this free?&lt;br&gt;
What happens after processing?&lt;br&gt;
Can I trust this product?&lt;/p&gt;

&lt;p&gt;If the first screen is confusing, the user leaves.&lt;/p&gt;

&lt;p&gt;There is no long onboarding.&lt;/p&gt;

&lt;p&gt;There is no second chance.&lt;/p&gt;

&lt;p&gt;That is why every tool page needs to be simple:&lt;/p&gt;

&lt;p&gt;Clear title.&lt;br&gt;
Clear upload area.&lt;br&gt;
Clear primary action.&lt;br&gt;
Clear result screen.&lt;br&gt;
Clear next step.&lt;/p&gt;

&lt;p&gt;The best interface is not the one with the most elements.&lt;/p&gt;

&lt;p&gt;It is the one that removes doubt.&lt;/p&gt;

&lt;p&gt;*&lt;em&gt;3. Tools Should Not End at “Download”&lt;br&gt;
*&lt;/em&gt;&lt;br&gt;
One of the biggest lessons I learned is that most online tools stop too early.&lt;/p&gt;

&lt;p&gt;They process the file and show a download button.&lt;/p&gt;

&lt;p&gt;That works, but it misses a bigger opportunity.&lt;/p&gt;

&lt;p&gt;Real work usually has another step.&lt;/p&gt;

&lt;p&gt;After merging a PDF, the user may want to compress it.&lt;/p&gt;

&lt;p&gt;After compressing a PDF, they may want to sign it.&lt;/p&gt;

&lt;p&gt;After converting an image, they may want to crop it.&lt;/p&gt;

&lt;p&gt;After creating a document, they may want to export it as a PDF.&lt;/p&gt;

&lt;p&gt;So the result screen should not be a dead end.&lt;/p&gt;

&lt;p&gt;It should be the beginning of the next useful action.&lt;/p&gt;

&lt;p&gt;This is why I started connecting Kreotar’s tools more deeply with products like &lt;a href="https://kreotar.com/en/tools/office/kreopdf" rel="noopener noreferrer"&gt;KreoPDF&lt;/a&gt; and &lt;a href="https://kreotar.com/en/office/kreodoc" rel="noopener noreferrer"&gt;KreoDo&lt;/a&gt;c.&lt;/p&gt;

&lt;p&gt;A tool can solve one task.&lt;/p&gt;

&lt;p&gt;A connected workflow can help finish the whole job.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Browser-Based Tools Are More Powerful Than People Realize&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The browser is no longer just a place to read websites.&lt;/p&gt;

&lt;p&gt;*&lt;em&gt;Modern browsers can handle real productivity tasks:&lt;br&gt;
*&lt;/em&gt;&lt;br&gt;
PDF processing&lt;br&gt;
image editing&lt;br&gt;
file conversion&lt;br&gt;
document creation&lt;br&gt;
compression&lt;br&gt;
signing&lt;br&gt;
annotations&lt;br&gt;
local file handling&lt;br&gt;
workflow-based actions&lt;/p&gt;

&lt;p&gt;This changes what a web product can be.&lt;/p&gt;

&lt;p&gt;Instead of forcing users to install heavy desktop software for every small file task, many actions can happen directly in the browser.&lt;/p&gt;

&lt;p&gt;This is one of the reasons I believe browser-based productivity tools have a strong future.&lt;/p&gt;

&lt;p&gt;They are accessible.&lt;/p&gt;

&lt;p&gt;They are fast to open.&lt;/p&gt;

&lt;p&gt;They work across devices.&lt;/p&gt;

&lt;p&gt;And when implemented correctly, they can reduce unnecessary complexity.&lt;/p&gt;

&lt;p&gt;*&lt;em&gt;5. Privacy Is a Product Feature&lt;br&gt;
*&lt;/em&gt;&lt;br&gt;
Many online tools ask users to upload files without making them feel safe.&lt;/p&gt;

&lt;p&gt;But files are not always casual.&lt;/p&gt;

&lt;p&gt;They may be:&lt;/p&gt;

&lt;p&gt;contracts&lt;br&gt;
invoices&lt;br&gt;
personal documents&lt;br&gt;
business reports&lt;br&gt;
client files&lt;br&gt;
academic work&lt;br&gt;
internal company material&lt;/p&gt;

&lt;p&gt;When people work with these files, trust matters.&lt;/p&gt;

&lt;p&gt;This is why privacy-first thinking is important.&lt;/p&gt;

&lt;p&gt;If a file task can happen locally in the browser, the user should not always need unnecessary server-side processing.&lt;/p&gt;

&lt;p&gt;The technical side matters, but the user-facing message is simple:&lt;/p&gt;

&lt;p&gt;Your file should feel safe.&lt;br&gt;
Your workflow should feel controlled.&lt;br&gt;
Your tool should feel trustworthy.&lt;/p&gt;

&lt;p&gt;Privacy is not only a technical decision.&lt;/p&gt;

&lt;p&gt;It is part of the product experience.&lt;/p&gt;

&lt;p&gt;*&lt;em&gt;6. SEO Helps People Find You, but UX Makes Them Stay&lt;br&gt;
*&lt;/em&gt;&lt;br&gt;
Programmatic SEO can bring visibility.&lt;/p&gt;

&lt;p&gt;But visibility alone is not enough.&lt;/p&gt;

&lt;p&gt;If users land on a page and the tool feels broken, slow, confusing, or generic, they will leave.&lt;/p&gt;

&lt;p&gt;That means every SEO page must still behave like a real product page.&lt;/p&gt;

&lt;p&gt;It should not be only text.&lt;/p&gt;

&lt;p&gt;It should have:&lt;/p&gt;

&lt;p&gt;a working tool&lt;br&gt;
helpful context&lt;br&gt;
clear instructions&lt;br&gt;
related tools&lt;br&gt;
next actions&lt;br&gt;
good mobile experience&lt;br&gt;
fast loading&lt;br&gt;
understandable copy&lt;/p&gt;

&lt;p&gt;SEO brings the user to the door.&lt;/p&gt;

&lt;p&gt;UX decides whether they enter.&lt;/p&gt;

&lt;p&gt;Product quality decides whether they come back.&lt;/p&gt;

&lt;p&gt;*&lt;em&gt;7. Internal Linking Is Product Architecture, Not Just SEO&lt;br&gt;
*&lt;/em&gt;&lt;br&gt;
When you build hundreds of tools, internal links are not only for search engines.&lt;/p&gt;

&lt;p&gt;They are also part of the user journey.&lt;/p&gt;

&lt;p&gt;A PDF compression tool should naturally connect to:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://kreotar.com/en/tools/office/kreopdf" rel="noopener noreferrer"&gt;PDF editor&lt;br&gt;
&lt;/a&gt;&lt;br&gt;
PDF protector&lt;br&gt;
PDF merger&lt;br&gt;
PDF to Word&lt;br&gt;
KreoPDF&lt;/p&gt;

&lt;p&gt;An image converter should naturally connect to:&lt;/p&gt;

&lt;p&gt;image cropper&lt;br&gt;
image resizer&lt;br&gt;
background remover&lt;br&gt;
image to PDF&lt;br&gt;
future image studio&lt;/p&gt;

&lt;p&gt;A document tool should connect to:&lt;/p&gt;

&lt;p&gt;PDF export&lt;br&gt;
&lt;a href="https://kreotar.com/en/office/kreodoc" rel="noopener noreferrer"&gt;KreoDoc&lt;/a&gt;&lt;br&gt;
signature tools&lt;br&gt;
conversion tools&lt;/p&gt;

&lt;p&gt;Internal linking helps users understand what they can do next.&lt;/p&gt;

&lt;p&gt;It also helps the product feel like an ecosystem instead of a random collection of pages.&lt;/p&gt;

&lt;p&gt;*&lt;em&gt;8. A Tool Website Can Become a Productivity Ecosystem&lt;br&gt;
*&lt;/em&gt;&lt;br&gt;
A simple tool website usually works like this:&lt;/p&gt;

&lt;p&gt;User arrives.&lt;br&gt;
User uploads a file.&lt;br&gt;
User downloads the result.&lt;br&gt;
User leaves.&lt;/p&gt;

&lt;p&gt;That is useful, but limited.&lt;/p&gt;

&lt;p&gt;A productivity ecosystem works differently:&lt;/p&gt;

&lt;p&gt;User arrives for one task.&lt;br&gt;
The result opens the next useful action.&lt;br&gt;
The user discovers a studio.&lt;br&gt;
The user starts building a workflow.&lt;br&gt;
The user returns because the system helps them finish more work.&lt;/p&gt;

&lt;p&gt;That is the direction I want to take Kreotar.&lt;/p&gt;

&lt;p&gt;Not just tools.&lt;/p&gt;

&lt;p&gt;PDF tools, document tools, image tools, converters, studios, and eventually workflows that work together.&lt;/p&gt;

&lt;p&gt;*&lt;em&gt;9. The Hardest Part Is Not Code. It Is Consistency.&lt;br&gt;
*&lt;/em&gt;&lt;br&gt;
As a solo founder, the challenge is not only technical.&lt;/p&gt;

&lt;p&gt;The challenge is staying consistent.&lt;/p&gt;

&lt;p&gt;You have to think about:&lt;/p&gt;

&lt;p&gt;product design&lt;br&gt;
development&lt;br&gt;
SEO&lt;br&gt;
marketing&lt;br&gt;
UX&lt;br&gt;
performance&lt;br&gt;
mobile experience&lt;br&gt;
content&lt;br&gt;
analytics&lt;br&gt;
user feedback&lt;br&gt;
positioning&lt;/p&gt;

&lt;p&gt;Every day, there is something to improve.&lt;/p&gt;

&lt;p&gt;A broken link.&lt;br&gt;
A weak title.&lt;br&gt;
A slow page.&lt;br&gt;
A confusing button.&lt;br&gt;
A missing next step.&lt;br&gt;
A tool that needs better UX.&lt;/p&gt;

&lt;p&gt;This is where discipline matters.&lt;/p&gt;

&lt;p&gt;Building a product is not one big heroic moment.&lt;/p&gt;

&lt;p&gt;It is a long series of small improvements.&lt;/p&gt;

&lt;p&gt;*&lt;em&gt;10. Technical Language Must Become Human Language&lt;br&gt;
*&lt;/em&gt;&lt;br&gt;
As developers, we often describe products with technical words:&lt;/p&gt;

&lt;p&gt;local-first&lt;br&gt;
browser-native&lt;br&gt;
client-side processing&lt;br&gt;
AI-assisted&lt;br&gt;
workflow-driven&lt;/p&gt;

&lt;p&gt;These words matter, but users usually care about simpler outcomes:&lt;/p&gt;

&lt;p&gt;Can I finish faster?&lt;br&gt;
Is my file safe?&lt;br&gt;
Do I need to install anything?&lt;br&gt;
Can I continue the next step easily?&lt;br&gt;
Will this save me time?&lt;/p&gt;

&lt;p&gt;So I’m learning to translate technical ideas into user benefits.&lt;/p&gt;

&lt;p&gt;Browser-native means no installation.&lt;/p&gt;

&lt;p&gt;Local-first means better privacy.&lt;/p&gt;

&lt;p&gt;Connected tools mean less tab switching.&lt;/p&gt;

&lt;p&gt;Workflows mean finishing tasks faster.&lt;/p&gt;

&lt;p&gt;That translation is important.&lt;/p&gt;

&lt;p&gt;A product is not valuable because it sounds technical.&lt;/p&gt;

&lt;p&gt;It is valuable because it solves a real problem clearly.&lt;/p&gt;

&lt;p&gt;*&lt;em&gt;11. The Future Is Not Just More Features&lt;br&gt;
*&lt;/em&gt;&lt;br&gt;
It is tempting to keep adding features.&lt;/p&gt;

&lt;p&gt;But more features can also create more confusion.&lt;/p&gt;

&lt;p&gt;The real question is:&lt;/p&gt;

&lt;p&gt;What should the user do next?&lt;/p&gt;

&lt;p&gt;If the product can answer that clearly, it becomes more useful.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;p&gt;The user compressed a PDF.&lt;/p&gt;

&lt;p&gt;Should they download it?&lt;/p&gt;

&lt;p&gt;Maybe.&lt;/p&gt;

&lt;p&gt;But they may also want to:&lt;/p&gt;

&lt;p&gt;open it in &lt;a href="https://kreotar.com/en/tools/office/kreopdf" rel="noopener noreferrer"&gt;KreoPDF&lt;/a&gt;&lt;br&gt;
sign it&lt;br&gt;
protect it&lt;br&gt;
make the pages consistent&lt;br&gt;
convert it&lt;br&gt;
save it as part of a workflow&lt;/p&gt;

&lt;p&gt;The future of online tools is not only about feature count.&lt;/p&gt;

&lt;p&gt;It is about guiding users from problem to finished work.&lt;/p&gt;

&lt;p&gt;*&lt;em&gt;12. What I Would Tell Other Solo Founders&lt;br&gt;
*&lt;/em&gt;&lt;br&gt;
If you are building a large tool-based product, I would say this:&lt;/p&gt;

&lt;p&gt;Do not only build pages.&lt;/p&gt;

&lt;p&gt;Build systems.&lt;/p&gt;

&lt;p&gt;Do not only add tools.&lt;/p&gt;

&lt;p&gt;Connect them.&lt;/p&gt;

&lt;p&gt;Do not only think about traffic.&lt;/p&gt;

&lt;p&gt;Think about what happens after the user arrives.&lt;/p&gt;

&lt;p&gt;Do not only optimize for search engines.&lt;/p&gt;

&lt;p&gt;Optimize for trust.&lt;/p&gt;

&lt;p&gt;Do not only create features.&lt;/p&gt;

&lt;p&gt;Create outcomes.&lt;/p&gt;

&lt;p&gt;Because users remember the tool that helped them finish the task.&lt;/p&gt;

&lt;p&gt;Final Thoughts&lt;/p&gt;

&lt;p&gt;Building 260+ online tools taught me that scale is not only about the number of pages, tools, or features.&lt;/p&gt;

&lt;p&gt;True scale comes from connection.&lt;/p&gt;

&lt;p&gt;A tool becomes more valuable when it leads to the next useful step.&lt;/p&gt;

&lt;p&gt;A product becomes more memorable when it helps users finish real work.&lt;/p&gt;

&lt;p&gt;That is what I’m building with Kreotar&lt;br&gt;
.&lt;/p&gt;

&lt;p&gt;A browser-based productivity ecosystem for PDFs, documents, images, converters, and connected workflows.&lt;/p&gt;

&lt;p&gt;Still early.&lt;/p&gt;

&lt;p&gt;Still improving every day.&lt;/p&gt;

&lt;p&gt;But the direction is clear:&lt;/p&gt;

&lt;p&gt;Not just more tools.&lt;/p&gt;

&lt;p&gt;Better workflows.&lt;br&gt;
&lt;a href="https://kreotar.com" rel="noopener noreferrer"&gt;KREOTAR&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webperf</category>
      <category>productivity</category>
      <category>startup</category>
    </item>
    <item>
      <title>Why I’m Building a Browser-Native Productivity Platform for File Workflows</title>
      <dc:creator>göktürk kahriman</dc:creator>
      <pubDate>Wed, 15 Apr 2026 11:41:33 +0000</pubDate>
      <link>https://forem.com/gktrk_kahriman_192cb6da/why-im-building-a-browser-native-productivity-platform-for-file-workflows-2blf</link>
      <guid>https://forem.com/gktrk_kahriman_192cb6da/why-im-building-a-browser-native-productivity-platform-for-file-workflows-2blf</guid>
      <description>&lt;p&gt;Most online tools solve only one step.&lt;/p&gt;

&lt;p&gt;You upload a file.&lt;br&gt;
You convert it.&lt;br&gt;
You download it.&lt;br&gt;
Then you realize you still need another tool.&lt;/p&gt;

&lt;p&gt;Maybe the PDF is too large.&lt;br&gt;
Maybe it needs a signature.&lt;br&gt;
Maybe it should be protected with a password.&lt;br&gt;
Maybe you need to convert it again.&lt;/p&gt;

&lt;p&gt;So you open another website.&lt;/p&gt;

&lt;p&gt;That experience is broken.&lt;/p&gt;

&lt;p&gt;This is one of the reasons I’m building Kreotar&lt;br&gt;
, a browser-based productivity platform for PDFs, documents, images, converters, and connected workflows.&lt;/p&gt;

&lt;p&gt;The Problem With Traditional Online Tools&lt;/p&gt;

&lt;p&gt;Most file tools are built like isolated utilities.&lt;/p&gt;

&lt;p&gt;They are useful, but they usually stop too early.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;p&gt;Compress a PDF&lt;br&gt;
Download it&lt;br&gt;
Open another tool&lt;br&gt;
Upload it again&lt;br&gt;
Sign it&lt;br&gt;
Download it again&lt;br&gt;
Open another tool&lt;br&gt;
Protect it&lt;br&gt;
Download the final version&lt;/p&gt;

&lt;p&gt;That is not a workflow.&lt;/p&gt;

&lt;p&gt;That is friction.&lt;/p&gt;

&lt;p&gt;A better experience should feel more like this:&lt;/p&gt;

&lt;p&gt;Open file → fix problem → continue next step → export final result&lt;/p&gt;

&lt;p&gt;That is the direction I believe online productivity tools are moving toward.&lt;/p&gt;

&lt;p&gt;*&lt;em&gt;Why Browser-Based Tools Are Becoming More Powerful&lt;br&gt;
*&lt;/em&gt;&lt;br&gt;
The browser is no longer just a place to read websites.&lt;/p&gt;

&lt;p&gt;Modern browsers can handle serious productivity tasks:&lt;/p&gt;

&lt;p&gt;PDF editing&lt;br&gt;
image processing&lt;br&gt;
file conversion&lt;br&gt;
document creation&lt;br&gt;
compression&lt;br&gt;
signing&lt;br&gt;
annotations&lt;br&gt;
local processing&lt;br&gt;
workflow automation&lt;/p&gt;

&lt;p&gt;This creates a huge opportunity.&lt;/p&gt;

&lt;p&gt;Instead of forcing users to install heavy software or jump between multiple websites, more tasks can happen directly inside the browser.&lt;/p&gt;

&lt;p&gt;That is the foundation behind Kreotar&lt;br&gt;
.&lt;/p&gt;

&lt;p&gt;*&lt;em&gt;Privacy Should Be Part of the Product&lt;br&gt;
*&lt;/em&gt;&lt;br&gt;
When users work with files, trust matters.&lt;/p&gt;

&lt;p&gt;A PDF might contain a contract.&lt;br&gt;
A document might contain private notes.&lt;br&gt;
An image might be personal.&lt;br&gt;
A business report might contain sensitive information.&lt;/p&gt;

&lt;p&gt;Not every file should be uploaded somewhere just to perform a simple action.&lt;/p&gt;

&lt;p&gt;That is why browser-based and local-first workflows matter.&lt;/p&gt;

&lt;p&gt;The technical explanation is simple:&lt;/p&gt;

&lt;p&gt;If the browser can process the file safely, the user should not need unnecessary server-side friction.&lt;/p&gt;

&lt;p&gt;But the user-facing explanation is even simpler:&lt;/p&gt;

&lt;p&gt;Your file should feel fast, safe, and under your control.&lt;/p&gt;

&lt;p&gt;Tools Are Useful. Workflows Are More Valuable.&lt;/p&gt;

&lt;p&gt;A single tool can solve a small problem.&lt;/p&gt;

&lt;p&gt;A workflow can solve the full job.&lt;/p&gt;

&lt;p&gt;That is the difference I’m focusing on while building &lt;a href="https://kreotar.com/en" rel="noopener noreferrer"&gt;Kreotar.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;p&gt;Compress PDF → Open in &lt;a href="https://kreotar.com/en/tools/office/kreopdf" rel="noopener noreferrer"&gt;KreoPDF&lt;/a&gt; → Sign → Protect → Download&lt;/p&gt;

&lt;p&gt;Or:&lt;/p&gt;

&lt;p&gt;Image to PDF → Crop → Compress → Open in KreoPDF → Export&lt;/p&gt;

&lt;p&gt;Or:&lt;/p&gt;

&lt;p&gt;Document creation → Export PDF → Sign → Share&lt;/p&gt;

&lt;p&gt;The goal is not only to provide many tools.&lt;/p&gt;

&lt;p&gt;The goal is to make those tools work together.&lt;/p&gt;

&lt;p&gt;What I’m Learning as a Founder&lt;/p&gt;

&lt;p&gt;One lesson became clear very quickly:&lt;/p&gt;

&lt;p&gt;Technical features are not enough.&lt;/p&gt;

&lt;p&gt;As developers, we often say things like:&lt;/p&gt;

&lt;p&gt;local-first&lt;br&gt;
browser-native&lt;br&gt;
AI-assisted&lt;br&gt;
client-side processing&lt;br&gt;
workflow-driven&lt;/p&gt;

&lt;p&gt;But users usually ask a much simpler question:&lt;/p&gt;

&lt;p&gt;*&lt;em&gt;Why should I care?&lt;br&gt;
*&lt;/em&gt;&lt;br&gt;
So I’m learning to translate technical ideas into real outcomes:&lt;/p&gt;

&lt;p&gt;Technical Idea  User Benefit&lt;br&gt;
Browser-native  No installation&lt;br&gt;
Local-first Better privacy&lt;br&gt;
Connected tools Less tab switching&lt;br&gt;
AI-assisted Less manual work&lt;br&gt;
Workflows   Finish tasks faster&lt;/p&gt;

&lt;p&gt;That shift matters.&lt;/p&gt;

&lt;p&gt;A product is not valuable because it sounds advanced.&lt;/p&gt;

&lt;p&gt;It is valuable when it helps someone finish their work faster.&lt;/p&gt;

&lt;p&gt;The Future of File Tools&lt;/p&gt;

&lt;p&gt;I think the future of online tools will not be just “more tools.”&lt;/p&gt;

&lt;p&gt;It will be:&lt;/p&gt;

&lt;p&gt;faster&lt;br&gt;
simpler&lt;br&gt;
more private&lt;br&gt;
more connected&lt;br&gt;
easier to use&lt;br&gt;
workflow-oriented&lt;br&gt;
accessible globally&lt;/p&gt;

&lt;p&gt;People do not want to think about which tool they need next.&lt;/p&gt;

&lt;p&gt;They want the next step to be obvious.&lt;/p&gt;

&lt;p&gt;That is what I’m trying to build with Kreotar&lt;br&gt;
.&lt;/p&gt;

&lt;p&gt;A user should be able to arrive for one simple task and continue naturally until the work is finished.&lt;/p&gt;

&lt;p&gt;*&lt;em&gt;Final Thought&lt;br&gt;
*&lt;/em&gt;&lt;br&gt;
The best products reduce friction.&lt;/p&gt;

&lt;p&gt;They do not make users feel like they are operating software.&lt;/p&gt;

&lt;p&gt;They make users feel like they are getting work done.&lt;/p&gt;

&lt;p&gt;That is the product direction I’m focused on:&lt;/p&gt;

&lt;p&gt;Not just online tools.&lt;br&gt;
Connected browser-based workflows.&lt;/p&gt;

&lt;p&gt;If you work with PDFs, documents, images, or file conversions, you can try Kreotar here:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://kreotar.com" rel="noopener noreferrer"&gt;kreotar&lt;/a&gt;&lt;/strong&gt;&lt;br&gt;
I’m still building and improving it every day.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>productivity</category>
      <category>startup</category>
    </item>
    <item>
      <title>The Browser Is Becoming the New Office Suite</title>
      <dc:creator>göktürk kahriman</dc:creator>
      <pubDate>Tue, 14 Apr 2026 06:41:33 +0000</pubDate>
      <link>https://forem.com/gktrk_kahriman_192cb6da/the-browser-is-becoming-the-new-office-suite-4ohp</link>
      <guid>https://forem.com/gktrk_kahriman_192cb6da/the-browser-is-becoming-the-new-office-suite-4ohp</guid>
      <description>&lt;p&gt;For years, online tools followed the same pattern:&lt;/p&gt;

&lt;p&gt;Upload a file.&lt;br&gt;
Wait.&lt;br&gt;
Convert it.&lt;br&gt;
Download it.&lt;br&gt;
Leave.&lt;/p&gt;

&lt;p&gt;It worked, but it never felt complete.&lt;/p&gt;

&lt;p&gt;Today, the way we work with documents is changing. People do not just want a PDF compressor, a converter, or a simple editor. They want to finish the entire task without jumping between five different websites.&lt;/p&gt;

&lt;p&gt;That is the idea behind Kreotar.&lt;/p&gt;

&lt;p&gt;Kreotar is being built as a browser-native productivity ecosystem where users can work with PDFs, documents, images, converters, and future AI workflows in one connected environment.&lt;/p&gt;

&lt;p&gt;*&lt;em&gt;Why Browser-Based Tools Matter&lt;br&gt;
*&lt;/em&gt;&lt;br&gt;
The browser is no longer just a place to read websites.&lt;/p&gt;

&lt;p&gt;Modern browsers can now handle serious productivity tasks:&lt;/p&gt;

&lt;p&gt;editing PDFs&lt;br&gt;
creating documents&lt;br&gt;
compressing files&lt;br&gt;
converting formats&lt;br&gt;
signing documents&lt;br&gt;
annotating pages&lt;br&gt;
working with images&lt;br&gt;
running local workflows&lt;/p&gt;

&lt;p&gt;This opens a powerful opportunity.&lt;/p&gt;

&lt;p&gt;Instead of forcing users to install heavy software or upload sensitive files to unknown servers, many tasks can happen directly inside the browser.&lt;/p&gt;

&lt;p&gt;That means faster access, less friction, and a better privacy experience.&lt;/p&gt;

&lt;p&gt;*&lt;em&gt;Privacy Is Becoming a Product Feature&lt;br&gt;
*&lt;/em&gt;&lt;br&gt;
Most people do not think about privacy until they upload something important.&lt;/p&gt;

&lt;p&gt;A contract.&lt;br&gt;
An invoice.&lt;br&gt;
A legal document.&lt;br&gt;
A personal file.&lt;br&gt;
A business report.&lt;/p&gt;

&lt;p&gt;At that moment, trust matters.&lt;/p&gt;

&lt;p&gt;A good online tool should not only be fast. It should also make the user feel safe.&lt;/p&gt;

&lt;p&gt;That is why Kreotar is focused on a privacy-first experience. Many tools are designed to work directly in the browser, helping users complete tasks without unnecessary server-side processing.&lt;/p&gt;

&lt;p&gt;The future of productivity is not only about more features.&lt;/p&gt;

&lt;p&gt;It is about trust.&lt;/p&gt;

&lt;p&gt;From Single Tools to Connected Workflows&lt;/p&gt;

&lt;p&gt;A common problem with online tools is that they solve only one step.&lt;/p&gt;

&lt;p&gt;You compress a PDF, then realize you need to edit it.&lt;br&gt;
You edit a document, then need to convert it.&lt;br&gt;
You sign a PDF, then need to protect it.&lt;br&gt;
You extract data, then need to organize it into a spreadsheet.&lt;/p&gt;

&lt;p&gt;This creates friction.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://kreotar.com" rel="noopener noreferrer"&gt;Kreotar&lt;/a&gt;&lt;/strong&gt; is designed around a different idea:&lt;/p&gt;

&lt;p&gt;Every tool should lead naturally to the next useful action.&lt;/p&gt;

&lt;p&gt;For example, after editing a PDF, a user should be able to compress it, crop it, protect it, standardize pages, or open it inside a dedicated PDF workspace without starting from zero.&lt;/p&gt;

&lt;p&gt;This is where simple tools become a real productivity system.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;KreoPDF and KreoDoc: The Core of the Ecosystem&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Two important parts of &lt;a href="https://kreotar.com" rel="noopener noreferrer"&gt;Kreotar’s&lt;/a&gt; direction are KreoPDF and KreoDoc.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://kreotar.com/en/tools/office/kreopdf" rel="noopener noreferrer"&gt;KreoPDF&lt;/a&gt; is being developed as a powerful browser-based PDF editor for editing, signing, annotating, organizing, compressing, and finalizing PDF files.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://kreotar.com/en/office/kreodoc" rel="noopener noreferrer"&gt;KreoDoc&lt;/a&gt; is focused on professional document creation and editing inside the browser.&lt;/p&gt;

&lt;p&gt;Together, they represent the bigger vision:&lt;/p&gt;

&lt;p&gt;Not just converting files.&lt;/p&gt;

&lt;p&gt;Actually working with them.&lt;/p&gt;

&lt;p&gt;The goal is to make the browser feel like a lightweight office environment — fast, accessible, and connected.&lt;/p&gt;

&lt;p&gt;*&lt;em&gt;Why Free Tools Still Matter&lt;br&gt;
*&lt;/em&gt;&lt;br&gt;
Some people say AI will replace online tools.&lt;/p&gt;

&lt;p&gt;I see it differently.&lt;/p&gt;

&lt;p&gt;AI will not remove the need for useful tools. It will make those tools smarter.&lt;/p&gt;

&lt;p&gt;People will still need to edit PDFs, create documents, convert files, compress images, sign contracts, and prepare professional outputs.&lt;/p&gt;

&lt;p&gt;The difference is that AI can help connect those actions.&lt;/p&gt;

&lt;p&gt;Instead of only asking, “What tool do I need?” users will be able to say:&lt;/p&gt;

&lt;p&gt;“Extract the data from this PDF and organize it into a spreadsheet.”&lt;/p&gt;

&lt;p&gt;“Turn this document into a professional report.”&lt;/p&gt;

&lt;p&gt;“Prepare this file for sending to my client.”&lt;/p&gt;

&lt;p&gt;That is the direction productivity software is moving toward.&lt;/p&gt;

&lt;p&gt;Tools are not disappearing.&lt;/p&gt;

&lt;p&gt;They are becoming workflows.&lt;/p&gt;

&lt;p&gt;*&lt;em&gt;The Vision for Kreotar&lt;br&gt;
*&lt;/em&gt;&lt;br&gt;
Kreotar is still early, but the direction is clear:&lt;/p&gt;

&lt;p&gt;A global, browser-native productivity platform with:&lt;/p&gt;

&lt;p&gt;PDF tools&lt;br&gt;
document tools&lt;br&gt;
image tools&lt;br&gt;
file converters&lt;br&gt;
AI-assisted workflows&lt;br&gt;
privacy-first processing&lt;br&gt;
connected studios&lt;br&gt;
future team and API features&lt;/p&gt;

&lt;p&gt;The goal is not to build another random tool directory.&lt;/p&gt;

&lt;p&gt;The goal is to build a system where users can start with one small task and naturally continue until the whole job is finished.&lt;/p&gt;

&lt;p&gt;*&lt;em&gt;Final Thought&lt;br&gt;
*&lt;/em&gt;&lt;br&gt;
The future of productivity software may not be one giant application.&lt;/p&gt;

&lt;p&gt;It may be a collection of fast, focused, connected tools that work together beautifully inside the browser.&lt;/p&gt;

&lt;p&gt;That is what I am building with Kreotar.&lt;/p&gt;

&lt;p&gt;A simpler way to work with files.&lt;br&gt;
A faster way to finish document tasks.&lt;br&gt;
A more private way to use online tools.&lt;/p&gt;

&lt;p&gt;Try it here:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://kreotar.com" rel="noopener noreferrer"&gt;https://kreotar.com&lt;/a&gt;&lt;/p&gt;

</description>
      <category>kreotar</category>
      <category>webdev</category>
      <category>productivity</category>
      <category>buildinpublic</category>
    </item>
    <item>
      <title>Why I Stopped Installing CLI Tools for File Processing (And Started Using WebAssembly)</title>
      <dc:creator>göktürk kahriman</dc:creator>
      <pubDate>Mon, 13 Apr 2026 06:00:00 +0000</pubDate>
      <link>https://forem.com/gktrk_kahriman_192cb6da/why-i-stopped-installing-cli-tools-for-file-processing-and-started-using-webassembly-3mkm</link>
      <guid>https://forem.com/gktrk_kahriman_192cb6da/why-i-stopped-installing-cli-tools-for-file-processing-and-started-using-webassembly-3mkm</guid>
      <description>&lt;h1&gt;
  
  
  Why I Stopped Installing CLI Tools for File Processing (And Started Using WebAssembly)
&lt;/h1&gt;

&lt;p&gt;Last month I deleted &lt;code&gt;node_modules&lt;/code&gt; from a project that only needed to merge three PDFs. The folder was 847MB. For a task that took 0.4 seconds to complete.&lt;/p&gt;

&lt;p&gt;We've normalized this insanity. We install gigabytes of dependencies, fight version conflicts, and audit security vulnerabilities just to perform basic file operations. All because we accepted that "real" processing requires "real" software—installed, maintained, and constantly updated.&lt;/p&gt;

&lt;p&gt;I stopped accepting it. Here's what replaced 264 CLI tools in my workflow.&lt;/p&gt;

&lt;h2&gt;
  
  
  The WebAssembly Tipping Point
&lt;/h2&gt;

&lt;p&gt;WebAssembly (WASM) hit 3.0 in December 2025 [^3^]. It now runs on 5.5% of all websites visited by Chrome users—and that number is accelerating [^11^]. But most developers still associate it with browser games or C++ ports. They miss the infrastructure shift.&lt;/p&gt;

&lt;p&gt;Modern browsers can execute near-native code using your device's actual hardware. Not emulated. Not virtualized. Your GPU, your RAM, your CPU cores—running FFmpeg, ImageMagick, and PDF engines directly in a sandboxed tab [^2^][^8^].&lt;/p&gt;

&lt;p&gt;The implications are architectural, not incremental.&lt;/p&gt;

&lt;h2&gt;
  
  
  What "Client-Side" Actually Means
&lt;/h2&gt;

&lt;p&gt;When I say "browser-based," developers assume I mean "uploads to a server, then downloads the result." That's the old model. I'm talking about zero-upload processing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;No network latency&lt;/strong&gt;: 47 images compress in 12 seconds, not 12 minutes waiting for cloud queues&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No server dependency&lt;/strong&gt;: Works offline on airplanes, in coffee shops, or air-gapped facilities&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No data exposure&lt;/strong&gt;: Files never leave your device because they never need to [^9^]&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The security model is elimination, not protection. When there's no server, there's nothing to breach. This isn't privacy by policy—it's privacy by architecture.&lt;/p&gt;

&lt;h2&gt;
  
  
  Replacing My Entire Toolkit
&lt;/h2&gt;

&lt;p&gt;I migrated my workflow to &lt;a href="https://kreotar.com" rel="noopener noreferrer"&gt;Kreotar&lt;/a&gt;, a suite of 264+ utilities running entirely in browser sandboxes. Here's what actually changed:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;PDF Workflows&lt;/strong&gt;: Merging, splitting, and compressing used to require &lt;code&gt;pdftk&lt;/code&gt;, &lt;code&gt;qpdf&lt;/code&gt;, or cloud services with questionable terms. Now: drag, process locally, download. KreoPDF handles form creation, digital signatures, and OCR without a single HTTP request to external servers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Image Processing&lt;/strong&gt;: Batch operations that needed ImageMagick or Sharp now run via WebGL-accelerated WASM. 20MB HEIC files from iPhones compress to web-ready formats using my device's GPU, not AWS Lambda.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Developer Utilities&lt;/strong&gt;: JSON formatting, regex testing, Base64 encoding—operations that sent sensitive data to "free" websites now execute in isolated Web Workers. My logs stay in my browser.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Document Editing&lt;/strong&gt;: KreoDoc replaced my Word dependency for collaborative work. Real-time editing without forcing IP through Microsoft's cloud. WebAssembly speed opens 100-page documents in under a second.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Performance Reality
&lt;/h2&gt;

&lt;p&gt;I benchmarked the same operations across three approaches:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Operation&lt;/th&gt;
&lt;th&gt;Cloud Tool&lt;/th&gt;
&lt;th&gt;Local CLI&lt;/th&gt;
&lt;th&gt;WebAssembly (Browser)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Merge 12 PDFs&lt;/td&gt;
&lt;td&gt;45s + upload&lt;/td&gt;
&lt;td&gt;2.1s&lt;/td&gt;
&lt;td&gt;0.8s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Compress 47 images&lt;/td&gt;
&lt;td&gt;8 min queue&lt;/td&gt;
&lt;td&gt;14s&lt;/td&gt;
&lt;td&gt;12s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Convert 4K video&lt;/td&gt;
&lt;td&gt;12 min&lt;/td&gt;
&lt;td&gt;3.2s&lt;/td&gt;
&lt;td&gt;2.9s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Regex test on 10MB log&lt;/td&gt;
&lt;td&gt;3s (upload)&lt;/td&gt;
&lt;td&gt;0.1s&lt;/td&gt;
&lt;td&gt;0.012s&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The browser wins because it removes the network hop. Your M-series Mac or Ryzen laptop isn't waiting for a Virginia data center—it &lt;em&gt;is&lt;/em&gt; the data center [^10^].&lt;/p&gt;

&lt;h2&gt;
  
  
  Why This Matters for Development Workflows
&lt;/h2&gt;

&lt;p&gt;We tell users to "install our app" or "use our API" without questioning if either is necessary. WebAssembly challenges that assumption:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;For DevOps&lt;/strong&gt;: Format conversion without spinning up containers. No Dockerfiles for one-off tasks.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;For Frontend Teams&lt;/strong&gt;: Image optimization without configuring Sharp or maintaining build pipelines.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;For Security&lt;/strong&gt;: File analysis without trusting third-party services with proprietary data. Your client's confidential documents never touch infrastructure you don't control.&lt;/p&gt;

&lt;p&gt;The browser has become a legitimate runtime environment. Not a document viewer. Not a JavaScript sandbox. A hardware-accelerated, secure execution environment that 4.9 billion people already have installed [^9^].&lt;/p&gt;

&lt;h2&gt;
  
  
  The Bigger Pattern: Edge-Heavy Computing
&lt;/h2&gt;

&lt;p&gt;We're witnessing the pendulum swing back from cloud-centralized to client-heavy processing [^4^][^10^]. Not because developers miss local installations, but because browsers matured into runtime environments capable of executing complex algorithms faster than 2015-era desktops.&lt;/p&gt;

&lt;p&gt;The next generation of tools won't require &lt;code&gt;npm install&lt;/code&gt;. They'll require &lt;code&gt;Ctrl+D&lt;/code&gt; (bookmark). They won't ask for API keys. They'll ask for optional, revocable File System Access permissions.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://kreotar.com" rel="noopener noreferrer"&gt;Kreotar&lt;/a&gt; is a proof of concept: 264 professional-grade utilities, zero backend infrastructure, zero user data collection. If we can replace ImageMagick, FFmpeg, and PDFtk with browser-based implementations, what else can we move off the server?&lt;/p&gt;

&lt;p&gt;Your build pipeline? Your design tools? Your IDE?&lt;/p&gt;

&lt;p&gt;*&lt;em&gt;## Try It&lt;br&gt;
*&lt;/em&gt;&lt;br&gt;
Your laptop is already a supercomputer. Stop renting inferior clouds to do what your device handles in milliseconds.&lt;/p&gt;

&lt;p&gt;No registration required. No data uploaded. Just your browser's untapped potential.&lt;/p&gt;

&lt;p&gt;*&lt;em&gt;**&lt;a href="https://kreotar.com" rel="noopener noreferrer"&gt;kreotar.com&lt;/a&gt;&lt;/em&gt;*&lt;/p&gt;

&lt;h2&gt;
  
  
  **
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;What's your experience with WebAssembly in production? Drop a comment if you've replaced CLI tools with browser-based alternatives.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>webassembly</category>
      <category>productivity</category>
      <category>webdev</category>
      <category>security</category>
    </item>
    <item>
      <title>I Processed 50M Files Without Installing a Single NPM Package (Or Renting a Server)</title>
      <dc:creator>göktürk kahriman</dc:creator>
      <pubDate>Sun, 12 Apr 2026 13:28:07 +0000</pubDate>
      <link>https://forem.com/gktrk_kahriman_192cb6da/i-processed-50m-files-without-installing-a-single-npm-package-or-renting-a-server-lj5</link>
      <guid>https://forem.com/gktrk_kahriman_192cb6da/i-processed-50m-files-without-installing-a-single-npm-package-or-renting-a-server-lj5</guid>
      <description>&lt;p&gt;You know the drill. You need to merge three PDFs for a client deliverable. Five minutes later, you're npm install-ing a 400MB Puppeteer dependency, fighting Chromium headless mode on your M2 Mac, and watching node_modules crawl across your SSD like digital mold.&lt;br&gt;
By the time the script runs, you've pulled 847 sub-dependencies, three of which have critical security vulnerabilities according to npm audit. For a task that should take 0.4 seconds.&lt;br&gt;
We've accepted this as "modern development." We trade disk space, security surface area, and coffee-break waiting times for the privilege of not installing Adobe Acrobat.&lt;br&gt;
But what if the best runtime for utility scripts isn't Node.js, Python, or Docker? What if it's the browser tab you already have open?&lt;br&gt;
&lt;strong&gt;The Architecture of Impatience&lt;br&gt;
*&lt;em&gt;Last year, I watched a developer compress a batch of images for a web deployment. The workflow:&lt;br&gt;
Upload 47 images to a "free" SaaS tool&lt;br&gt;
Wait for Wi-Fi to push 800MB to Virginia&lt;br&gt;
Download the compressed versions&lt;br&gt;
Realize the metadata wasn't preserved&lt;br&gt;
Repeat&lt;br&gt;
Total time: 18 minutes. Total dependencies installed: 0. Total control over the process: also 0.&lt;br&gt;
This is the hidden tax of cloud-native convenience. We offloaded computation to servers we don't control, introduced network latency into operations that should be instantaneous, and called it "serverless."&lt;br&gt;
Real serverless is running FFmpeg in your browser without a Docker container.&lt;br&gt;
**WebAssembly Isn't the Future—It's the Patch&lt;br&gt;
**WebAssembly (WASM) arrived promising "near-native performance in the browser." Most developers heard "video games in Chrome" and tuned out. They missed the infrastructure revolution.&lt;br&gt;
When you compile C++, Rust, or Go to WASM, you're not creating a web app. You're creating a binary that executes in a sandboxed, zero-trust environment using the host machine's bare metal. Your browser becomes a secure runtime that can:&lt;br&gt;
Execute video encoding (FFmpeg.wasm) faster than Electron apps&lt;br&gt;
Process PDFs using C++ libraries compiled for the web&lt;br&gt;
Manipulate images via WebGL-accelerated filters&lt;br&gt;
Run regex engines and JSON parsers at native speeds&lt;br&gt;
All without node_modules. All without docker run. All without sending your client's confidential files to a server in another jurisdiction.&lt;br&gt;
The 50M File Experiment&lt;br&gt;
We built Kreotar to test a hypothesis: Could we replace 264 common developer and productivity utilities with browser-native implementations? Not wrappers around API calls—actual client-side processing.&lt;br&gt;
The stack:&lt;br&gt;
WebAssembly for compute-intensive operations (PDF rendering, image compression, video codecs)&lt;br&gt;
Web Workers for parallel processing (multi-threading without blocking the UI)&lt;br&gt;
IndexedDB for temporary local storage (offline capability)&lt;br&gt;
Service Workers for instant loading and offline functionality&lt;br&gt;
The result? 50 million files processed. Zero servers rented. Zero data breaches possible (nothing to breach).&lt;br&gt;
Here's what that means practically:&lt;br&gt;
The JSON Formatter That Works Offline&lt;br&gt;
You paste a malformed 10MB API response. Traditional web tools? Upload, parse server-side, return formatted JSON. Kreotar? WebAssembly-based parser runs locally in 12ms. Works on airplane Wi-Fi that barely loads Slack.&lt;br&gt;
Regex Testing Without RegExr.com&lt;br&gt;
Your pattern matches against sensitive log files. Instead of pasting production data into a third-party website (and hoping their analytics don't capture it), the regex engine executes in a sandboxed Worker. Your logs never leave the tab.&lt;br&gt;
Video Conversion on a Chromebook&lt;br&gt;
Need to strip audio from an MP4 for a presentation? FFmpeg.wasm runs in the browser using the device's GPU acceleration. A $300 Chromebook processes video faster than a 2019 MacBook Pro running cloud-based conversion tools.&lt;br&gt;
Why Your Browser Is the Better Runtime&lt;br&gt;
Node.js revolutionized development by bringing JavaScript to the server. But for utility scripts—file conversion, format validation, image manipulation—we went backwards. We installed gigabytes of dependencies to do tasks the browser could handle natively.&lt;br&gt;
Consider the security model:&lt;br&gt;
CLI Tool Approach:&lt;br&gt;
Installs 300 dependencies&lt;br&gt;
Requires filesystem access&lt;br&gt;
Runs with user-level permissions&lt;br&gt;
Updates break workflows&lt;br&gt;
Browser-WASM Approach:&lt;br&gt;
Zero installation&lt;br&gt;
Sandboxed execution (no filesystem access beyond Downloads)&lt;br&gt;
Runs in isolated origin context&lt;br&gt;
Updates are cache-busted Service Worker refreshes&lt;br&gt;
Or the performance model:&lt;br&gt;
**Docker Approach:&lt;br&gt;
**Spin up container (2-5 seconds)&lt;br&gt;
Mount volumes&lt;br&gt;
Process file&lt;br&gt;
Clean up container&lt;br&gt;
**Browser Approach:&lt;br&gt;
**Drag file into tab&lt;br&gt;
WebAssembly processes using local GPU (0.4 seconds)&lt;br&gt;
Download result&lt;br&gt;
The browser isn't just a document viewer anymore. It's a secure, sandboxed, hardware-accelerated runtime environment that 4.9 billion people already have installed.&lt;br&gt;
**The Developer Workflow Shift&lt;br&gt;
**This changes how we think about "tools." Instead of maintaining a graveyard of Homebrew packages—each with conflicting dependencies and deprecation notices—you maintain a bookmarks folder of utilities that:&lt;br&gt;
Never need updates (the browser handles versioning)&lt;br&gt;
Work identically on macOS, Linux, Windows, and iPad&lt;br&gt;
Process files using your local hardware (faster than cloud for most operations)&lt;br&gt;
Respect your privacy by architectural necessity&lt;br&gt;
For DevOps engineers, this means format conversion without spinning up Lambda functions. For frontend developers, it means image optimization without configuring Sharp. For security teams, it means file analysis without trusting third-party services with proprietary data.&lt;br&gt;
**The Privacy-Performance Convergence&lt;br&gt;
**We've been told to choose between privacy and convenience. Either use slow local tools or fast cloud services that monetize your data.&lt;br&gt;
WebAssembly breaks this false dichotomy. Kreotar processes files faster than cloud alternatives because there's no network hop. The privacy isn't a feature—it's a side effect of the architecture. When computation happens in your browser's WASM sandbox, there is no server to subpoena, no database to leak, no employee to misuse access.&lt;br&gt;
50 million files processed without a single upload isn't a marketing claim. It's a technical impossibility for traditional SaaS architecture.&lt;br&gt;
**The Future Is Client-Heavy&lt;br&gt;
**We're witnessing the pendulum swing back from cloud-centralized computing to edge-heavy processing. Not because developers miss the complexity of local installations, but because browsers have matured into legitimate runtime environments.&lt;br&gt;
The next generation of developer tools won't require npm install. They'll require Ctrl+D (bookmark). They won't ask for API keys. They'll ask for File System Access API permissions (optional, revocable).&lt;br&gt;
*&lt;/em&gt;&lt;a href="https://kreotar.com" rel="noopener noreferrer"&gt;Kreotar&lt;/a&gt;&lt;/strong&gt; is a proof of concept: 264 professional-grade utilities, zero backend infrastructure, zero user data collection. If we can replace ImageMagick, FFmpeg, and PDFtk with browser-based implementations, what else can we move off the server?&lt;br&gt;
Your build pipeline? Your design tools? Your IDE?&lt;br&gt;
The browser is already a supercomputer. Stop renting inferior clouds to do what your laptop can handle in milliseconds.&lt;br&gt;
Try the zero-install toolkit: &lt;a href="https://kreotar.com" rel="noopener noreferrer"&gt;kreotar.com&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webassembly</category>
      <category>javascript</category>
      <category>productivity</category>
      <category>privacy</category>
    </item>
    <item>
      <title>Client-Side vs Server-Side: When Is Browser Processing Actually Better?</title>
      <dc:creator>göktürk kahriman</dc:creator>
      <pubDate>Sat, 11 Apr 2026 18:00:00 +0000</pubDate>
      <link>https://forem.com/gktrk_kahriman_192cb6da/client-side-vs-server-side-when-is-browser-processing-actually-better-1ep4</link>
      <guid>https://forem.com/gktrk_kahriman_192cb6da/client-side-vs-server-side-when-is-browser-processing-actually-better-1ep4</guid>
      <description>&lt;p&gt;I built a company on client-side processing. I still server-side process half my traffic. Here's the honest breakdown.&lt;br&gt;
**When Browser Processing Wins&lt;br&gt;
**Privacy-first workflows. Medical images, legal docs, personal photos. If leaking the data destroys trust, process locally.&lt;br&gt;
Offline or spotty connectivity. My tools work in airplanes, basements, rural Kenya. Serverless literally means "no server to fail."&lt;br&gt;
Instant feedback loops. Image filters, text analysis, code formatters. Sub-100ms response times beat any API roundtrip.&lt;br&gt;
When Server-Side Wins (And I Admit It)&lt;br&gt;
Batch processing. Converting 500 images? Your laptop will thermal throttle. My server farm won't.&lt;br&gt;
Proprietary models. I can't ship GPT-4 or Stable Diffusion in a 200KB WASM chunk. Yet.&lt;br&gt;
Persistent storage. Browsers clear IndexedDB "when they feel like it." My databases don't.&lt;br&gt;
The Hybrid Truth&lt;br&gt;
&lt;a href="https://kreotar.com" rel="noopener noreferrer"&gt;Kreotar's&lt;/a&gt; real architecture isn't client-side OR server-side. It's client-side-first with server-side-escape-hatches:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User uploads file
    ↓
&amp;lt; 50MB? → WASM processing locally
&amp;gt; 50MB? → Encrypted stream to server, process, return, forget
    ↓
Result delivered
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The server doesn't store. It processes and amnesia. But it exists because some jobs are too heavy for a phone.&lt;br&gt;
Where Browser Processing Surprises You&lt;br&gt;
&lt;strong&gt;Cold starts:&lt;/strong&gt; A WASM module loads faster than a Lambda function warms up. First user pays the cost, not every user.&lt;br&gt;
Parallelism: 8 Web Workers on an M3 MacBook beat a single server core for embarrassingly parallel tasks (image resizing, format conversion).&lt;br&gt;
&lt;strong&gt;Cost:&lt;/strong&gt; My browser users cost me $0 in compute. My server users cost me $0.002 per job. At scale, that matters.&lt;br&gt;
One Thing I'd Do Differently&lt;br&gt;
I spent months trying to make video processing work in browser. It doesn't, reliably, for files &amp;gt;100MB. I should have built the server fallback earlier instead of pretending WASM would magically improve.&lt;br&gt;
**Question ?&lt;br&gt;
**Is "process in browser" becoming a UX pattern users actually recognize and trust? Or are we still educating? I see "no upload required" badges converting 40% better than "fast processing." But I can't tell if users understand why that's good.&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>webdev</category>
      <category>programming</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Process PDFs in Browser Without Uploading: A Practical Guide</title>
      <dc:creator>göktürk kahriman</dc:creator>
      <pubDate>Sat, 11 Apr 2026 12:00:00 +0000</pubDate>
      <link>https://forem.com/gktrk_kahriman_192cb6da/process-pdfs-in-browser-without-uploading-a-practical-guide-36gc</link>
      <guid>https://forem.com/gktrk_kahriman_192cb6da/process-pdfs-in-browser-without-uploading-a-practical-guide-36gc</guid>
      <description>&lt;p&gt;I built this because I watched a lawyer upload a client's contract to a "free PDF tool" with a .ru domain. Never again.&lt;br&gt;
&lt;a href="https://kreotar.com" rel="noopener noreferrer"&gt;What We're Building&lt;br&gt;
&lt;/a&gt;A browser-based PDF processor that extracts text, merges pages, and adds watermarks. Zero server roundtrips. The PDF never leaves the machine.&lt;br&gt;
&lt;strong&gt;Step 1: The Library&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;
&lt;span class="c1"&gt;// pdf-lib handles manipulation, pdfjs-dist handles extraction&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;PDFDocument&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pdf-lib&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;pdfjs&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pdfjs-dist&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// pdfjs needs its worker loaded manually in most bundlers&lt;/span&gt;
&lt;span class="nx"&gt;pdfjs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;GlobalWorkerOptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;workerSrc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`https://cdnjs.cloudflare.com/ajax/libs/pdf.js/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;pdfjs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;version&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/pdf.worker.min.js`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 2: Read Without Uploading&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;processLocalPDF&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// File stays in browser memory only&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;arrayBuffer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;arrayBuffer&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;pdf&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;PDFDocument&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;arrayBuffer&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Extract text from page 1&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;pdfJsDoc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;pdfjs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getDocument&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;arrayBuffer&lt;/span&gt; &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nx"&gt;promise&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;pdfJsDoc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getPage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;textContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getTextContent&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;textContent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;str&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt; &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;*&lt;em&gt;Step 3: Modify and Download&lt;br&gt;
*&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;watermarkAndSave&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pdfBytes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;watermarkText&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;pdf&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;PDFDocument&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pdfBytes&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;pages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;pdf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getPages&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="c1"&gt;// Add watermark to each page&lt;/span&gt;
  &lt;span class="nx"&gt;pages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;drawText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;watermarkText&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;y&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getHeight&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;r&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;g&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;b&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.1&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="na"&gt;opacity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;modified&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;pdf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;save&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="c1"&gt;// Trigger download, no server involved&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;blob&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Blob&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nx"&gt;modified&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;application/pdf&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;URL&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createObjectURL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;blob&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;a&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;href&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;download&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;processed.pdf&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;click&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nx"&gt;URL&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;revokeObjectURL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;*&lt;em&gt;The Gotcha *&lt;/em&gt;&lt;br&gt;
PDFs with embedded fonts are 10x larger in memory than their file size. A 5MB PDF can balloon to 80MB when pdf-lib parses it. I cap processing at 50MB input files—above that, I warn users that their tab might crash.&lt;br&gt;
**One Thing I'd Do Differently&lt;br&gt;
**I initially tried to parse PDFs with regex. Don't. The spec is 800 pages of chaos. Use the libraries. They're battle-tested by Mozilla and maintained by people who've read the spec so you don't have to.&lt;br&gt;
**Question ?&lt;br&gt;
**Has anyone solved client-side PDF creation from scratch (not manipulation) at reasonable speeds? Generating a 100-page report from JSON data takes 4 seconds in my tests. Acceptable, but feels wrong.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>productivity</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>I Built 243 Browser Tools with WASM. Here's What Broke.</title>
      <dc:creator>göktürk kahriman</dc:creator>
      <pubDate>Sat, 11 Apr 2026 07:12:05 +0000</pubDate>
      <link>https://forem.com/gktrk_kahriman_192cb6da/i-built-243-browser-tools-with-wasm-heres-what-broke-1n6g</link>
      <guid>https://forem.com/gktrk_kahriman_192cb6da/i-built-243-browser-tools-with-wasm-heres-what-broke-1n6g</guid>
      <description>&lt;p&gt;The first 50 tools worked great. Tool #51—a PDF form filler—crashed Safari because I assumed 2GB of WASM memory was standard. It's not. iOS kills tabs at 1.4GB.&lt;br&gt;
What I Got Wrong&lt;br&gt;
I architected &lt;a href="//kreotar.com"&gt;Kreotar&lt;/a&gt; around the belief that "client-side = unlimited scale." Wrong. Browsers are weird, capricious beasts. Each has its own memory ceiling, its own CORS paranoia, its own idea of what "background processing" means.&lt;br&gt;
The Architecture That Survived&lt;/p&gt;

&lt;p&gt;┌─────────────────┐&lt;br&gt;
│   UI Layer      │  (React, disposable)&lt;br&gt;
├─────────────────┤&lt;br&gt;
│   Worker Pool   │  (4-8 Web Workers, spawn/kill aggressively)&lt;br&gt;
├─────────────────┤&lt;br&gt;
│   WASM Bridge   │  (Emscripten, -sALLOW_MEMORY_GROWTH=1)&lt;br&gt;
├─────────────────┤&lt;br&gt;
│   Tool Modules  │  (Lazy-loaded, 200KB chunks max)&lt;br&gt;
└─────────────────┘&lt;br&gt;
The bridge layer was the surprise hero. I initially compiled each tool as a standalone WASM blob. Tool #87 (HEIC converter) was 14MB. First load: 8 seconds on 4G. Dead on arrival.&lt;br&gt;
Now tools stream. WASM compiles on first use, not page load. Users wait once per tool, not once per visit.&lt;br&gt;
&lt;strong&gt;What Actually Failed&lt;/strong&gt;&lt;br&gt;
FFmpeg in browser: 18MB WASM, 6-minute compile on mobile. Moved to server-side for videos &amp;gt;100MB. I admit defeat.&lt;br&gt;
SharedArrayBuffer: Required for true parallel processing. Still blocked by default in Firefox with certain extensions. Had to build a fallback that uses postMessage and feels 40% slower.&lt;br&gt;
File System Access API: Chrome-only. My "seamless local file editing" feature works for 60% of users. I ship it anyway with a graceful degradation to downloads.&lt;br&gt;
One Thing I'd Do Differently&lt;br&gt;
I spent three weeks optimizing WASM build flags before realizing the bottleneck was DOM thrashing. Profile your actual app, not your benchmarks.&lt;br&gt;
The Genuine Question&lt;br&gt;
Has anyone found a reliable way to detect "this browser tab is about to be killed by the OS" before it happens? I've tried memory pressure APIs, performance.memory, heartbeat workers. All garbage.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>buildinpublic</category>
      <category>react</category>
    </item>
    <item>
      <title>How to compress PDFs in the browser without uploading to servers: A complete guide</title>
      <dc:creator>göktürk kahriman</dc:creator>
      <pubDate>Fri, 10 Apr 2026 18:30:00 +0000</pubDate>
      <link>https://forem.com/gktrk_kahriman_192cb6da/how-to-compress-pdfs-in-the-browser-without-uploading-to-servers-a-complete-guide-51d6</link>
      <guid>https://forem.com/gktrk_kahriman_192cb6da/how-to-compress-pdfs-in-the-browser-without-uploading-to-servers-a-complete-guide-51d6</guid>
      <description>&lt;p&gt;Your PDFs contain sensitive data. Tax forms, contracts, medical records. Yet most online tools want you to upload them to mysterious servers in who-knows-where.&lt;br&gt;
I built Kreotar's PDF compressor to solve this exact paranoia. Everything happens in your browser. Here's exactly how you can implement the same architecture.&lt;br&gt;
Step 1: The Architecture Decision&lt;br&gt;
We use PDF-lib (client-side JS) combined with custom WASM modules for image compression. The key is handling everything in a Web Worker so the UI stays responsive during heavy processing.&lt;br&gt;
JavaScript&lt;br&gt;
Copy&lt;br&gt;
// pdf-processor.worker.js&lt;br&gt;
import * as PDFLib from 'pdf-lib';&lt;br&gt;
import { PDFDocument } from 'pdf-lib';&lt;br&gt;
import { createImageCompressionWasm } from './wasm-image-compress';&lt;/p&gt;

&lt;p&gt;self.onmessage = async (event) =&amp;gt; {&lt;br&gt;
  const { fileBuffer, quality = 0.7 } = event.data;&lt;/p&gt;

&lt;p&gt;try {&lt;br&gt;
    const pdfDoc = await PDFDocument.load(fileBuffer);&lt;br&gt;
    const pages = pdfDoc.getPages();&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let totalSaved = 0;

// Process each page
for (let i = 0; i &amp;lt; pages.length; i++) {
  const page = pages[i];

  // Extract images from page
  const images = await extractImagesFromPage(page);

  for (const image of images) {
    const originalSize = image.data.length;

    // Compress using WASM (mozjpeg compiled to WASM)
    const compressed = await createImageCompressionWasm({
      data: image.data,
      quality: quality * 100,
      format: 'jpeg'
    });

    totalSaved += (originalSize - compressed.length);

    // Replace image in PDF
    await replaceImageInPage(page, image.ref, compressed);
  }

  // Report progress
  self.postMessage({ 
    type: 'progress', 
    current: i + 1, 
    total: pages.length 
  });
}

const pdfBytes = await pdfDoc.save();

self.postMessage({ 
  type: 'complete', 
  result: pdfBytes,
  compressionRatio: totalSaved / fileBuffer.length
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;} catch (error) {&lt;br&gt;
    self.postMessage({ type: 'error', message: error.message });&lt;br&gt;
  }&lt;br&gt;
};&lt;br&gt;
Step 2: The React Integration&lt;br&gt;
Here's how to wire it up in your frontend:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useRef&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useCallback&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;PdfWorker&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./pdf-processor.worker?worker&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;PdfCompressor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setStatus&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;idle&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;progress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setProgress&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;compressionStats&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setCompressionStats&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;workerRef&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useRef&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;processPdf&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useCallback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;setStatus&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;processing&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;setProgress&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Initialize worker&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;worker&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;PdfWorker&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nx"&gt;workerRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;worker&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// Read file as ArrayBuffer&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;arrayBuffer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;arrayBuffer&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;worker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onmessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;total&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;compressionRatio&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="k"&gt;switch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;progress&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="nf"&gt;setProgress&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nx"&gt;total&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
          &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;complete&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="nf"&gt;setStatus&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;complete&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="nf"&gt;setCompressionStats&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
              &lt;span class="na"&gt;originalSize&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;size&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
              &lt;span class="na"&gt;newSize&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
              &lt;span class="na"&gt;ratio&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;compressionRatio&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;
            &lt;span class="p"&gt;});&lt;/span&gt;

            &lt;span class="c1"&gt;// Create download blob&lt;/span&gt;
            &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;blob&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Blob&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;application/pdf&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
            &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;URL&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createObjectURL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;blob&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="c1"&gt;// Auto-download&lt;/span&gt;
            &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;a&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;href&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;download&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`compressed-&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;click&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="nx"&gt;URL&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;revokeObjectURL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="nx"&gt;worker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;terminate&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
          &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="nf"&gt;setStatus&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="nf"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
            &lt;span class="nx"&gt;worker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;terminate&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;};&lt;/span&gt;

      &lt;span class="c1"&gt;// Start processing&lt;/span&gt;
      &lt;span class="nx"&gt;worker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;postMessage&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; 
        &lt;span class="na"&gt;fileBuffer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;arrayBuffer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;quality&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.7&lt;/span&gt; &lt;span class="c1"&gt;// Compression quality&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;arrayBuffer&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt; &lt;span class="c1"&gt;// Transfer ownership for performance&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[]);&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;pdf-compressor&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt; 
        &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;file&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; 
        &lt;span class="nx"&gt;accept&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;.pdf&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; 
        &lt;span class="nx"&gt;onChange&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;?.[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nf"&gt;processPdf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;])}&lt;/span&gt;
        &lt;span class="nx"&gt;disabled&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;processing&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;processing&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;progress-bar&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;progress&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;%`&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;span&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;progress&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="nx"&gt;compressed&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/span&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="p"&gt;)}&lt;/span&gt;

      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;compressionStats&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;stats&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;Original&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{(&lt;/span&gt;&lt;span class="nx"&gt;compressionStats&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;originalSize&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toFixed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt; &lt;span class="nx"&gt;KB&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;Saved&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;compressionStats&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ratio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toFixed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="o"&gt;%&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="p"&gt;)}&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Step 3: Handling the Gotchas&lt;br&gt;
Memory limits: Browsers crash around 2GB of RAM usage. For large PDFs, I process pages in chunks:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Handle large PDFs in chunks to avoid memory crashes&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;processInChunks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pages&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;chunkSize&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;

  &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;pages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nx"&gt;chunkSize&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;chunk&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;pages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;chunkSize&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Force garbage collection between chunks (hacky but necessary)&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;processed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;chunk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;processPage&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="nx"&gt;results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;processed&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;results&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;CORS issues: If your WASM module is on a CDN, ensure proper headers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;
Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Embedder-Policy: require-corp
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Privacy Win&lt;br&gt;
Your file never leaves your laptop. Check the Network tab in DevTools - zero uploads. That's the magic of client-side processing.&lt;br&gt;
I made the mistake early on of trying to use serverless functions for this. The latency killed the UX. Plus, who wants to upload their tax documents to a random Lambda function?&lt;br&gt;
Try it yourself: &lt;a href="https://kreotar.com/en/tools/pdf/compress" rel="noopener noreferrer"&gt;Kreotar PDF Compressor&lt;/a&gt;&lt;br&gt;
What other PDF operations are you trying to client-side? I might already have a tool for it in the sitemap above.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>productivity</category>
      <category>ai</category>
    </item>
    <item>
      <title>I built 47 developer tools running entirely in WebAssembly. Here's the architecture that made it possible.</title>
      <dc:creator>göktürk kahriman</dc:creator>
      <pubDate>Fri, 10 Apr 2026 16:25:11 +0000</pubDate>
      <link>https://forem.com/gktrk_kahriman_192cb6da/i-built-47-developer-tools-running-entirely-in-webassembly-heres-the-architecture-that-made-it-3lln</link>
      <guid>https://forem.com/gktrk_kahriman_192cb6da/i-built-47-developer-tools-running-entirely-in-webassembly-heres-the-architecture-that-made-it-3lln</guid>
      <description>&lt;p&gt;I messed up the first iteration. Badly.&lt;br&gt;
When I started building &lt;a href="https://kreotar.com" rel="noopener noreferrer"&gt;Kreotar's&lt;/a&gt; developer toolkit (JSON formatter, Base64 encoder, hash generators - you know the drill), I thought "hey, let's just use standard JavaScript string manipulation." Fast forward to processing a 50MB JSON file, and I watched the main thread freeze like a deer in headlights. The browser tab became unresponsive for 8 seconds. Users were angry. I was embarrassed.&lt;br&gt;
That's when I went all-in on WebAssembly.&lt;br&gt;
The WASM Architecture Behind the Tools&lt;br&gt;
Instead of parsing heavy text operations in JS, I compiled Rust code to WASM for the heavy lifting. Here's the core architecture:&lt;br&gt;
rust&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nd"&gt;#[wasm_bindgen]&lt;/span&gt;
&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;format_json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;indent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;usize&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;JsValue&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nn"&gt;serde_json&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;serde_json&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;from_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;.map_err&lt;/span&gt;&lt;span class="p"&gt;(|&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nn"&gt;JsValue&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;from_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nd"&gt;format!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Parse error: {}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;formatted&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;serde_json&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;to_string_pretty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;.map_err&lt;/span&gt;&lt;span class="p"&gt;(|&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nn"&gt;JsValue&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;from_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nd"&gt;format!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Format error: {}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;formatted&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;wrap&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="nv"&gt;'comlink&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;import&lt;/span&gt; &lt;span class="n"&gt;wasmWorker&lt;/span&gt; &lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="err"&gt;'.&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;wasm&lt;/span&gt;&lt;span class="py"&gt;.worker&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="n"&gt;worker&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;useWasmTool&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;processing&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;setProcessing&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;processData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;operation&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;setProcessing&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;worker&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;wasmWorker&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;wasmModule&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;wrap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;worker&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;wasmModule&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;operation&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="n"&gt;finally&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;setProcessing&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;processData&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;processing&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Why This Matters&lt;br&gt;
The Base64 encoder handles 100MB files in under 2 seconds. The JSON formatter validates nested structures without crashing the tab. The hash generators (SHA-256, MD5, etc.) process files locally - your data never touches my server.&lt;br&gt;
I learned the hard way that JSON.parse() has limits. WASM doesn't magically fix everything, but when combined with Web Workers, it creates a truly non-blocking experience.&lt;br&gt;
The "oops" moment: I initially tried to pass massive strings directly between JS and WASM. Memory copying killed performance. Switching to SharedArrayBuffer for large payloads changed everything. Here's the pattern that actually works:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;processLargeFile&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fileBuffer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;wasmMemory&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;WebAssembly&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Memory&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; 
    &lt;span class="na"&gt;initial&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;256&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="na"&gt;maximum&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;512&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;shared&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; 
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;wasmModule&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;process_buffer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;wasmMemory&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What I'm building next: A client-side regex tester that can handle multi-line 10MB log files without lag. Because waiting 5 seconds for a regex match is unacceptable.&lt;br&gt;
What's your WASM use case? I'm curious if others are hitting these same JS performance walls.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Privacy Policy | Kreotar</title>
      <dc:creator>göktürk kahriman</dc:creator>
      <pubDate>Fri, 10 Apr 2026 11:01:00 +0000</pubDate>
      <link>https://forem.com/gktrk_kahriman_192cb6da/privacy-policy-kreotar-5a8c</link>
      <guid>https://forem.com/gktrk_kahriman_192cb6da/privacy-policy-kreotar-5a8c</guid>
      <description>&lt;p&gt;Building trust starts with clarity. Kreotar's ultra-specific privacy policy gives developers and enterprises the transparency they need to innovate safely. Dive into the details and see the difference.&lt;/p&gt;

</description>
      <category>tools</category>
      <category>productivity</category>
      <category>tech</category>
    </item>
  </channel>
</rss>
