<?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: Aribu js</title>
    <description>The latest articles on Forem by Aribu js (@digital-abetka).</description>
    <link>https://forem.com/digital-abetka</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%2F3897149%2F87471e61-187e-4615-8b84-038086a00cd0.png</url>
      <title>Forem: Aribu js</title>
      <link>https://forem.com/digital-abetka</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/digital-abetka"/>
    <language>en</language>
    <item>
      <title>AI WordPress Hosting Management via Linux CLI</title>
      <dc:creator>Aribu js</dc:creator>
      <pubDate>Sat, 02 May 2026 07:25:46 +0000</pubDate>
      <link>https://forem.com/digital-abetka/ai-wordpress-hosting-management-via-linux-cli-1gh6</link>
      <guid>https://forem.com/digital-abetka/ai-wordpress-hosting-management-via-linux-cli-1gh6</guid>
      <description>&lt;p&gt;Hello DEV community! 👋 I'll start with the most important thing (and mandatory for transparency): &lt;em&gt;this article contains affiliate links. If you decide to buy hosting through my link, I'll receive a small commission that will help support this blog, and you'll get an incredibly powerful platform. Win-win!&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;If you're a professional developer, a WordPress agency owner, or just a geek who loves maximum automation, you definitely know this pain: endless tab switching. You write code in the terminal, then jump into the browser, log in to the hosting control panel, find the necessary site, check the PHP version, look at the logs... It's horribly disrupting your flow.&lt;/p&gt;

&lt;p&gt;But what if your terminal became smart? What if you could just ask the AI to make infrastructure changes? The Pressable company has just rolled out a real technological bomb - &lt;strong&gt;AI-powered hosting management from Pressable&lt;/strong&gt; through the innovative Model Context Protocol (MCP).&lt;/p&gt;

&lt;p&gt;Today, I'll share my real, "battle-tested" experience of setting up this feature. This will be a deep, practical guide: from deploying a test site to connecting Gemini CLI in the Fedora Linux console, with a detailed analysis of typical errors and their elegant workarounds. Let's go! 🚀&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;h2&gt;What is Pressable and what's Automattic got to do with it?&lt;/h2&gt;
&lt;/h2&gt;

&lt;p&gt;Before diving into the terminal, it's worth understanding what we're working with. If you've been in web development for a long time, you know the company &lt;strong&gt;Automattic&lt;/strong&gt;. They're the giants behind &lt;strong&gt;&lt;a href="https://automattic.pxf.io/EEARXD" rel="noopener noreferrer"&gt;WordPress.com&lt;/a&gt;&lt;/strong&gt;, WooCommerce, Tumblr, and Jetpack.&lt;/p&gt;

&lt;p&gt;Pressable is their premium platform for &lt;strong&gt;Managed WordPress Hosting&lt;/strong&gt;. It's not just another "piece of server", it's an elite infrastructure created by the same people who write the WordPress core. There's no traditional cPanel; instead, the platform offers a custom, ultra-fast architecture, Edge Caching, and unprecedented stability, making it an ideal choice for large WooCommerce stores and high-load agencies.&lt;/p&gt;

&lt;p&gt;And now, this infrastructure has received native AI support.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;h2&gt;What is MCP and why is it a game-changer?&lt;/h2&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Model Context Protocol (MCP)&lt;/strong&gt; is an open standard with open-source code. It allows AI to securely and standardizedly connect to external databases, APIs, and tools.&lt;/p&gt;

&lt;p&gt;Pressable has integrated this protocol directly into their server architecture. Now, you can manage your WordPress sites through Claude Desktop, ChatGPT, or local AI terminals (like Gemini CLI), using ordinary human language.&lt;/p&gt;

&lt;p&gt;That's why this is critically important for modern workflow:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;No context-switching:&lt;/strong&gt; Ask for logs, create backups, change PHP versions, and manage plugins without leaving your favorite AI tool.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Open standard:&lt;/strong&gt; This is not a closed "proprietary" magic that binds you to one service. You choose which AI to use.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Free for all:&lt;/strong&gt; This powerful AI integration is available on all Pressable plans without any additional fees.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;We also recommend reading:&lt;/strong&gt; &lt;a href="https://shcho-i-yak.pp.ua/posts/svelte-5-ecosystem-review/" rel="noopener noreferrer"&gt;Review of the Svelte 5 ecosystem: What's new and why you should switch&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  &lt;h2&gt;Step 1: Preparing the platform and creating an API&lt;/h2&gt;
&lt;/h2&gt;

&lt;p&gt;Any experiment starts with a testing ground. After logging in to the Pressable panel, I created a new site - &lt;code&gt;shchoiyak-sandbox&lt;/code&gt; - in a matter of seconds. This is an ideal environment for testing scripts without risking the main project.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fshcho-i-yak.pp.ua%2Fimages%2Fuploads%2Fpressable-mcp-sandbox-creation.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fshcho-i-yak.pp.ua%2Fimages%2Fuploads%2Fpressable-mcp-sandbox-creation.webp" title="Deploying a test WordPress environment in Pressable" alt="Creating a test site shchoiyak-sandbox in the Pressable panel" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, we need a key for access. We go to the &lt;strong&gt;API Applications&lt;/strong&gt; section in the profile settings. There, I generated a &lt;strong&gt;Client ID&lt;/strong&gt; and &lt;strong&gt;Client Secret&lt;/strong&gt;. These keys will become our digital bridge between the local terminal and Automattic's servers.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fshcho-i-yak.pp.ua%2Fimages%2Fuploads%2Fpressable-mcp-api-keys.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fshcho-i-yak.pp.ua%2Fimages%2Fuploads%2Fpressable-mcp-api-keys.webp" title="Obtaining Client ID and Client Secret for API access" alt="Generating API Application keys in the Pressable panel" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;h2&gt;Step 2: Setting up the Linux environment and Google keys&lt;/h2&gt;
&lt;/h2&gt;

&lt;p&gt;For this case, I'm using the Fedora distribution with the KDE Plasma shell. To avoid cluttering the system with global packages, I follow the isolation rule: we create a separate workspace on the &lt;code&gt;DATA&lt;/code&gt; disk specifically for our AI assistant.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; /mnt/DATA/pressable-mcp-project
&lt;span class="nb"&gt;cd&lt;/span&gt; /mnt/DATA/pressable-mcp-project
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, I encountered the first interesting nuance, which is worth warning about. To run Gemini CLI, you need an API key from Google. I had an old key generated in Google Cloud (with a &lt;em&gt;Free trial&lt;/em&gt; status). And it gave me an &lt;code&gt;API Error: Content generator not initialized&lt;/code&gt; error.&lt;/p&gt;

&lt;p&gt;Why? Because when the 90-day trial in Cloud ends, Google "freezes" access. The secret lies in generating a key directly in the &lt;a href="https://aistudio.google.com/app/apikey" rel="noopener noreferrer"&gt;&lt;strong&gt;Google AI Studio&lt;/strong&gt;&lt;/a&gt; (with a &lt;em&gt;Free tier&lt;/em&gt; status), which is completely free and doesn't require a bank card.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fshcho-i-yak.pp.ua%2Fimages%2Fuploads%2Fpressable-mcp-google-keys.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fshcho-i-yak.pp.ua%2Fimages%2Fuploads%2Fpressable-mcp-google-keys.webp" title="It's essential to use the correct Free tier key from AI Studio" alt="Comparing the status of Free trial and Free tier keys in Google AI Studio" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After obtaining the correct key, I saved it in the system so it wouldn't get lost during sessions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gemini config &lt;span class="nb"&gt;set &lt;/span&gt;api_key &lt;span class="s2"&gt;"AIzaSy...working_key"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;h2&gt;Step 3: Pitfall 1 - 404 Error and npm&lt;/h2&gt;
&lt;/h2&gt;

&lt;p&gt;Next, we initialize the bridge. The idea was simple: add the MCP server via the &lt;code&gt;npx&lt;/code&gt; package manager, as described in the platform's early documentation.&lt;/p&gt;

&lt;p&gt;I entered the command:&lt;br&gt;
&lt;code&gt;gemini mcp add pressable npx -y @pressable/mcp-server&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;And immediately got a red text in the terminal: &lt;strong&gt;&lt;code&gt;npm error 404 Not Found&lt;/code&gt;&lt;/strong&gt;. The package simply disappeared from the official registry! As it turned out, Pressable's developers are rapidly evolving; they've updated the security architecture, and this old method of package distribution is no longer supported.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fshcho-i-yak.pp.ua%2Fimages%2Fuploads%2Fpressable-mcp-npm-error.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fshcho-i-yak.pp.ua%2Fimages%2Fuploads%2Fpressable-mcp-npm-error.webp" title="Typical error of outdated documentation: package not found" alt="404 error when trying to install the outdated @pressable/mcp-server package" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;We also recommend reading:&lt;/strong&gt; &lt;a href="https://shcho-i-yak.pp.ua/posts/integrate-ai-groq-api/" rel="noopener noreferrer"&gt;How to integrate AI into your web application using the Groq API&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  &lt;h2&gt;Step 4: Pitfall 2 - OAuth and stdio issue&lt;/h2&gt;
&lt;/h2&gt;

&lt;p&gt;Searching for an up-to-date workaround, I found their new utility &lt;code&gt;mcp-remote&lt;/code&gt;. This approach uses modern, secure OAuth authorization (like logging in through Google or Facebook).&lt;/p&gt;

&lt;p&gt;I ran the command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx &lt;span class="nt"&gt;-y&lt;/span&gt; mcp-remote@latest &lt;span class="o"&gt;[&lt;/span&gt;https://mcp.pressable.com/sse]&lt;span class="o"&gt;(&lt;/span&gt;https://mcp.pressable.com/sse&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The system worked incredibly smartly: it launched a local server on port &lt;code&gt;25181&lt;/code&gt;, automatically opened my browser, asked me to confirm access to my Pressable account (Authorize), successfully saved the access token, and... the MCP server still showed a &lt;code&gt;Disconnected&lt;/code&gt; status in Gemini CLI!&lt;/p&gt;

&lt;p&gt;Why did this magic end in disappointment? Because terminal agents (like our Gemini CLI) communicate with MCP servers through an extremely strict &lt;code&gt;stdio&lt;/code&gt; protocol. They expect an ideally clean data stream in JSON format. And the &lt;code&gt;mcp-remote&lt;/code&gt; script during authorization prints human-readable text ("Opening browser...", "Port 25181...") to the terminal, which completely "pollutes" and breaks the communication channel for the AI.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fshcho-i-yak.pp.ua%2Fimages%2Fuploads%2Fpressable-mcp-disconnected.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fshcho-i-yak.pp.ua%2Fimages%2Fuploads%2Fpressable-mcp-disconnected.webp" title="Conflict between stdio protocol and browser authorization script" alt="Disconnected MCP server status due to stdio protocol conflict" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;h2&gt;Step 5: The correct solution - Direct connection via SSE&lt;/h2&gt;
&lt;/h2&gt;

&lt;p&gt;In fact, Pressable's engineers have anticipated this scenario. They've created an ideal option specifically for terminal bots - &lt;strong&gt;direct connection via SSE&lt;/strong&gt; (Server-Sent Events), which doesn't require any crutches like npm packages or browser openings.&lt;/p&gt;

&lt;p&gt;Here's my tested step-by-step plan to get it working from the first try:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Log in to the &lt;strong&gt;&lt;a href="https://automattic.pxf.io/c/6341363/3864277/22744" rel="noopener noreferrer"&gt;my.pressable.com&lt;/a&gt;&lt;/strong&gt; panel.&lt;/li&gt;
&lt;li&gt;Go to the &lt;strong&gt;Tools → Pressable MCP&lt;/strong&gt; section and generate a new, single &lt;strong&gt;Access Token&lt;/strong&gt; (a long string of characters).&lt;/li&gt;
&lt;li&gt;In your terminal (while in the isolated project folder), add the server directly:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gemini mcp add pressable &lt;span class="o"&gt;[&lt;/span&gt;https://mcp.pressable.com]&lt;span class="o"&gt;(&lt;/span&gt;https://mcp.pressable.com&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="nt"&gt;--transport&lt;/span&gt; sse
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, you need to securely "feed" your Access Token to the AI agent. Gemini CLI stores its local settings in a hidden file &lt;code&gt;.gemini/settings.json&lt;/code&gt;. Open it with any editor (e.g., &lt;code&gt;nano&lt;/code&gt; or &lt;code&gt;kate&lt;/code&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nano .gemini/settings.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And add your token to the &lt;code&gt;headers&lt;/code&gt; block with the mandatory &lt;code&gt;Bearer&lt;/code&gt; prefix. The file should look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"mcpServers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"pressable"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"[https://mcp.pressable.com](https://mcp.pressable.com)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"headers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"Authorization"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Bearer YOUR_LONG_ACCESS_TOKEN_HERE"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Save the file, check the status with the command &lt;code&gt;gemini mcp list&lt;/code&gt;, and finally see the desired green &lt;strong&gt;Connected&lt;/strong&gt; indicator! Our bridge between AI and hosting is officially built.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fshcho-i-yak.pp.ua%2Fimages%2Fuploads%2Fpressable-mcp-connected-success.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fshcho-i-yak.pp.ua%2Fimages%2Fuploads%2Fpressable-mcp-connected-success.webp" title="Green light: direct SSE connection works perfectly" alt="Successful connection of the MCP server with a Connected status" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;h2&gt;Step 6: AI-Sysadmin in action - Site management&lt;/h2&gt;
&lt;/h2&gt;

&lt;p&gt;Now, the most delicious part. We launch the interactive chat with the command &lt;code&gt;gemini chat&lt;/code&gt; and give our agent a task in ordinary, natural English (the API works best with it):&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&amp;gt; Please list all the sites on my Pressable account and tell me the PHP version of shchoiyak-sandbox.&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Here, another cool feature of the MCP protocol itself is vividly demonstrated. The AI doesn't silently "take control" of your servers. It analyzes the request, understands that it needs the &lt;code&gt;get_account_site_counts&lt;/code&gt; tool from Pressable, and &lt;strong&gt;asks for your permission&lt;/strong&gt; to execute it (Action Required). I choose the option "Allow all server tools for this session" to give it a carte blanche for the current session.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fshcho-i-yak.pp.ua%2Fimages%2Fuploads%2Fpressable-mcp-action-required.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fshcho-i-yak.pp.ua%2Fimages%2Fuploads%2Fpressable-mcp-action-required.webp" title="AI always asks for confirmation before accessing the hosting API" alt="Gemini CLI request for permission to use server tools" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The agent receives raw, complex machine JSON from the Pressable API, filters it with its "brains" in milliseconds, and outputs a beautiful, structured response directly to the terminal:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Domain:&lt;/strong&gt; &lt;a href="https://shchoiyak-sandbox.mystagingwebsite.com" rel="noopener noreferrer"&gt;shchoiyak-sandbox.mystagingwebsite.com&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PHP Version:&lt;/strong&gt; 8.5&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;State:&lt;/strong&gt; live&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Datacenter:&lt;/strong&gt; BUR (Burbank, CA)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fshcho-i-yak.pp.ua%2Fimages%2Fuploads%2Fpressable-mcp-final-result.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fshcho-i-yak.pp.ua%2Fimages%2Fuploads%2Fpressable-mcp-final-result.webp" title="MCP magic: human-readable response based on complex infrastructure data" alt="Successful output of PHP version and site data in the console" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Without opening a browser, without passwords, and without navigating through the control panel menu, I got all the critical infrastructure information right in my command line!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;We also recommend reading:&lt;/strong&gt; &lt;a href="https://shcho-i-yak.pp.ua/posts/smm-turbo-instagram-editor/" rel="noopener noreferrer"&gt;SMM Turbo: How I created my own editor for Instagram carousels&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  &lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;/h2&gt;

&lt;p&gt;It's essential to understand the realities: Pressable's MCP technology doesn't replace a full-fledged visual hosting control panel for some complex or specific tasks. This is not a "magic button" that will launch your business for you.&lt;/p&gt;

&lt;p&gt;But it's a &lt;strong&gt;groundbreaking tool for optimizing your workflow&lt;/strong&gt; as a developer. The ability to delegate routine tasks (log checks, mass PHP version updates, staging environment deployments, backup management) directly from your IDE or terminal, where you write code, is a savings of dozens of hours of focused time per month. This is the end of the context-switching era.&lt;/p&gt;

&lt;p&gt;🔥 &lt;strong&gt;Want to take your WordPress projects to a radically new level of speed?&lt;/strong&gt;&lt;br&gt;
Ditch the routine and start managing your servers like a true AI ninja.&lt;/p&gt;

&lt;p&gt;💡 &lt;strong&gt;A quick tip from the author:&lt;/strong&gt; If you choose an annual plan, Pressable gives you 2 months absolutely free (you get 12 months of premium hosting for the price of 10). It's by far the smartest way to migrate to elite infrastructure!&lt;/p&gt;

&lt;p&gt;👉 &lt;strong&gt;&lt;a href="https://automattic.pxf.io/c/6341363/3864277/22744" rel="noopener noreferrer"&gt;Try AI hosting management by Pressable today&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;And if you need fast, stylish creatives for your website's social media, don't forget to use my free graphic editor &lt;strong&gt;&lt;a href="https://smm.shcho-i-yak.pp.ua" rel="noopener noreferrer"&gt;SMM Turbo&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>wordpress</category>
      <category>ai</category>
      <category>linux</category>
    </item>
    <item>
      <title>Svelte 5 Ecosystem: What's New &amp; Why Switch</title>
      <dc:creator>Aribu js</dc:creator>
      <pubDate>Mon, 27 Apr 2026 09:38:09 +0000</pubDate>
      <link>https://forem.com/digital-abetka/svelte-5-ecosystem-whats-new-why-switch-33m</link>
      <guid>https://forem.com/digital-abetka/svelte-5-ecosystem-whats-new-why-switch-33m</guid>
      <description>&lt;p&gt;Hello DEV community! 👋 If you're a frontend developer, you've probably noticed how quickly trends are changing. Just yesterday, we were arguing about what's better - React or Vue, and today more and more developers are choosing alternative paths. In my previous article, I talked about how I created my own graphic editor, and mentioned that "under the hood" it uses the latest Svelte.&lt;/p&gt;

&lt;p&gt;Today, I want to take a deep &lt;strong&gt;look at the Svelte 5 ecosystem&lt;/strong&gt;. We'll figure out what's changed, where the old compiler "magic" has gone, what runes (Runes) are, and most importantly, &lt;strong&gt;why you should switch&lt;/strong&gt; to this framework right now. Let's go. 🚀&lt;/p&gt;

&lt;h2&gt;
  
  
  Why is the Svelte 5 ecosystem the new standard?
&lt;/h2&gt;

&lt;p&gt;For a long time, Svelte 4 was my favorite. It compiled code into vanilla JavaScript, didn't have a virtual DOM, and worked extremely fast. But it had its own "childhood diseases". &lt;/p&gt;

&lt;p&gt;Reactivity was based on the &lt;code&gt;let&lt;/code&gt; keyword and reactive blocks &lt;code&gt;$:&lt;/code&gt;. It looked magical, but as soon as your application became more complex (like my graphic editor), this magic started to confuse. The Svelte 5 ecosystem solved this problem radically.&lt;/p&gt;

&lt;p&gt;The main feature of the fifth version is &lt;strong&gt;Fine-grained reactivity&lt;/strong&gt; based on signals. Now the framework updates only the parts of the DOM that have actually changed, without checking the entire component.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;We also recommend reading:&lt;/strong&gt; &lt;a href="https://shcho-i-yak.pp.ua/en/posts/smm-turbo-instagram-editor/" rel="noopener noreferrer"&gt;SMM Turbo: How I created my own editor for Instagram carousels&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The Magic of Runes (Runes): Goodbye, old syntax
&lt;/h2&gt;

&lt;p&gt;The biggest shock for framework veterans is the emergence of runes. The creators of Svelte 5 abandoned the old &lt;code&gt;let&lt;/code&gt; behavior in favor of explicit state indicators.&lt;/p&gt;

&lt;p&gt;What are runes? These are special functions that tell the compiler: "Here we have reactive data". &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;$state()&lt;/code&gt;&lt;/strong&gt; - replacement for the usual &lt;code&gt;let&lt;/code&gt; for reactive variables.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;$derived()&lt;/code&gt;&lt;/strong&gt; - replacement for &lt;code&gt;$:&lt;/code&gt;, used for computed values.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;$effect()&lt;/code&gt;&lt;/strong&gt; - a combination of life cycles (onMount, afterUpdate) that responds to changes in dependencies.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;$props()&lt;/code&gt;&lt;/strong&gt; - replacement for &lt;code&gt;export let&lt;/code&gt;, now props are received as an object.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fshcho-i-yak.pp.ua%2Fimages%2Fuploads%2Fsvelte-5-runes-code.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fshcho-i-yak.pp.ua%2Fimages%2Fuploads%2Fsvelte-5-runes-code.webp" title="Comparison of syntax: Svelte 4 vs Svelte 5" alt="Code snippet with Svelte 5 runes" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Look how elegant the code has become. Now reactivity is not tied to &lt;code&gt;.svelte&lt;/code&gt; files. You can extract &lt;code&gt;$state&lt;/code&gt; into a regular &lt;code&gt;.svelte.ts&lt;/code&gt; file (like I did for managing the history of Undo/Redo in SMM Turbo) and import it anywhere. This is a Game Changer.&lt;/p&gt;

&lt;h2&gt;
  
  
  What else is new under the hood?
&lt;/h2&gt;

&lt;p&gt;In addition to runes, the developers have significantly reworked other aspects of the framework to make it more predictable for large enterprise projects.&lt;/p&gt;

&lt;p&gt;Here are the key changes, why it's worth switching to the new version:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Snippets (Snippets):&lt;/strong&gt; Instead of old &lt;code&gt;&amp;lt;slot&amp;gt;&lt;/code&gt;, snippets &lt;code&gt;{#snippet name()}&lt;/code&gt; are now used. This allows you to pass pieces of markup as functions. Much more convenient for creating reusable UI components.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Event Handlers:&lt;/strong&gt; Goodbye &lt;code&gt;on:click&lt;/code&gt; directives. Now we use standard &lt;code&gt;onclick={handler}&lt;/code&gt; attributes, like in React. This improves typing and simplifies integration with TypeScript.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lightning speed:&lt;/strong&gt; Thanks to signals under the hood, memory usage has decreased, and rendering speed of complex lists has increased many times.&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;We also recommend reading:&lt;/strong&gt; &lt;a href="https://shcho-i-yak.pp.ua/en/posts/wordpress-com-plugins-all-paid-plans/" rel="noopener noreferrer"&gt;Revolution on WordPress.com: 50,000+ plugins now available on all paid plans&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  How Svelte 5 helped me create SMM Turbo
&lt;/h2&gt;

&lt;p&gt;When I designed the architecture of SMM Turbo, I needed a framework that could handle hundreds of DOM nodes (layers of text, images, backgrounds) on one screen, and at the same time not slow down during Drag &amp;amp; Drop.&lt;/p&gt;

&lt;p&gt;Thanks to the Svelte 5 ecosystem, I was able to create a global &lt;code&gt;editorState&lt;/code&gt; based on &lt;code&gt;$state&lt;/code&gt; and &lt;code&gt;$derived&lt;/code&gt;. When you drag a title onto the canvas, only the &lt;code&gt;x&lt;/code&gt; and &lt;code&gt;y&lt;/code&gt; coordinates of a specific element are updated. The rest of the interface doesn't even suspect changes and doesn't waste resources on redrawing.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fshcho-i-yak.pp.ua%2Fimages%2Fuploads%2Fsvelte-5-architecture-smm.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fshcho-i-yak.pp.ua%2Fimages%2Fuploads%2Fsvelte-5-architecture-smm.webp" title="File structure of SMM Turbo and work with global state" alt="Architecture of the application on Svelte 5" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And the transition to &lt;code&gt;onclick&lt;/code&gt; and normal event handling allowed me to easily attach global keyboard listeners (for shortcuts like &lt;code&gt;Ctrl+C&lt;/code&gt; / &lt;code&gt;Ctrl+V&lt;/code&gt;), without creating "crutches".&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;We also recommend reading:&lt;/strong&gt; &lt;a href="https://shcho-i-yak.pp.ua/en/posts/integrate-ai-groq-api/" rel="noopener noreferrer"&gt;How to integrate AI into your web application using Groq API&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Conclusion: Is it worth updating?
&lt;/h2&gt;

&lt;p&gt;My verdict is unequivocal - yes. The &lt;strong&gt;Svelte 5 ecosystem&lt;/strong&gt; has become more mature, predictable, and powerful. The transition to runes may seem unusual at first, but as soon as you feel the freedom to extract state beyond components, you'll never want to go back to the old compiler magic. &lt;/p&gt;

&lt;p&gt;If you're looking for a lightweight, fast, and modern tool for your next pet project or startup - this is the perfect choice.&lt;/p&gt;

&lt;p&gt;And to see what this framework is really capable of in the real world, check out my project, which is completely built on the new architecture.&lt;/p&gt;




&lt;h3&gt;
  
  
  🚀 Try SMM Turbo - built on Svelte 5
&lt;/h3&gt;

&lt;p&gt;Free AI editor for Instagram carousels, working lightning-fast right in the browser.&lt;br&gt;
👉 &lt;strong&gt;&lt;a href="https://smm.shcho-i-yak.pp.ua" rel="noopener noreferrer"&gt;Open SMM Turbo Editor (Free)&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;




</description>
      <category>svelte</category>
      <category>webdev</category>
      <category>javascript</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Building a Free Instagram Editor with Svelte 5, WASM, &amp; Llama 3.1</title>
      <dc:creator>Aribu js</dc:creator>
      <pubDate>Sat, 25 Apr 2026 11:53:20 +0000</pubDate>
      <link>https://forem.com/digital-abetka/building-a-free-instagram-editor-with-svelte-5-wasm-llama-31-14m7</link>
      <guid>https://forem.com/digital-abetka/building-a-free-instagram-editor-with-svelte-5-wasm-llama-31-14m7</guid>
      <description>&lt;p&gt;Hello DEV community! 👋 Building a web-based graphic editor usually means wrestling with HTML5 Canvas or heavy WebGL libraries. But what if you could bypass Canvas entirely, manipulate the DOM directly with pure CSS, wrap it in blazing-fast Svelte 5 runes, and inject local WASM for background removal?&lt;/p&gt;

&lt;p&gt;Today, I want to share the technical journey of building &lt;strong&gt;SMM Turbo&lt;/strong&gt; - a completely free, in-browser Instagram carousel editor. We'll look "under the hood" at SvelteKit state management, local AI image processing, Llama 3.1 integration via Groq API, and why I chose the DOM over Canvas for rendering. Let's dive in! 🚀&lt;/p&gt;

&lt;h2&gt;
  
  
  🏗 Architecture: DOM instead of Canvas
&lt;/h2&gt;

&lt;p&gt;If you've ever been interested in developing graphic editors, you know that the standard approach is to use HTML5 &lt;code&gt;&amp;lt;canvas&amp;gt;&lt;/code&gt; or special libraries like Fabric.js or Konva. But I took a different, somewhat rebellious path 🐧.&lt;/p&gt;

&lt;p&gt;In &lt;strong&gt;SMM Turbo&lt;/strong&gt;, the working area is ordinary HTML elements (&lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;span&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt;) that are positioned absolutely using &lt;code&gt;x&lt;/code&gt; and &lt;code&gt;y&lt;/code&gt; coordinates. &lt;/p&gt;

&lt;p&gt;Why so? Because &lt;strong&gt;CSS is a superpower!&lt;/strong&gt; 🦸‍♂️ &lt;/p&gt;

&lt;p&gt;Rendering through DOM allowed me to implement incredibly complex typography in just a few lines of code, instead of writing complex math for drawing pixels on Canvas. &lt;/p&gt;

&lt;p&gt;Here's what regular CSS gives you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Gradient text:&lt;/strong&gt; Using &lt;code&gt;-webkit-background-clip: text&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Stroke (outline):&lt;/strong&gt; Works through &lt;code&gt;-webkit-text-stroke&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Shadows and glow:&lt;/strong&gt; Elementary &lt;code&gt;drop-shadow&lt;/code&gt; and &lt;code&gt;text-shadow&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Text bending along a circle:&lt;/strong&gt; Implemented by breaking the text into separate &lt;code&gt;&amp;lt;span&amp;gt;&lt;/code&gt; elements using &lt;code&gt;transform: rotate(...) translateY(...)&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But how do you save the finished picture then? That's where the &lt;code&gt;html-to-image&lt;/code&gt; library comes in.&lt;/p&gt;

&lt;p&gt;Here's what my script for exporting to &lt;code&gt;+page.svelte&lt;/code&gt; looks like, which takes a "screenshot" of the DOM node, packs the slides into an archive using &lt;code&gt;JSZip&lt;/code&gt;, and converts them "on the fly":&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;options&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="nx"&gt;editor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;canvasWidth&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;editor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;canvasHeight&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;scale(1)&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;transformOrigin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;top left&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; 
    &lt;span class="na"&gt;pixelRatio&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="na"&gt;cacheBust&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="c1"&gt;// Draw Canvas from DOM&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;canvas&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;toCanvas&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// Save in the selected format (WebP/JPEG) with the desired quality&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;dataUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;canvas&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toDataURL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;editor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exportFormat&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;qualityDecimal&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;capturedImages&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;dataUrl&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Pack all slides into a ZIP archive&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;zip&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;JSZip&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;capturedImages&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;img&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="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;base64Data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;img&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&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="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="nx"&gt;zip&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`smm-slide-&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="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.webp`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;base64Data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;base64&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="p"&gt;});&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;content&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;zip&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generateAsync&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="s2"&gt;blob&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Thanks to this, we get perfect text quality, flexibility of CSS filters, and fast export of the entire carousel.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fshcho-i-yak.pp.ua%2Fimages%2Fuploads%2Fsmm-turbo-editor-interface.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fshcho-i-yak.pp.ua%2Fimages%2Fuploads%2Fsmm-turbo-editor-interface.webp" title="SMM Turbo working area: flexible typography settings and layers" alt="SMM Turbo editor interface with tools" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  🌍 Multilingualism with Runes: On-the-Fly Localization
&lt;/h2&gt;

&lt;p&gt;As the project expanded, there was a need to add an English version of the interface and landing page to attract an international audience. In the React or Vue ecosystem, you'd typically install heavy libraries like &lt;code&gt;i18next&lt;/code&gt; for this. But in Svelte 5, we can do it much more elegantly thanks to "runes".&lt;/p&gt;

&lt;p&gt;I created a simple localization service based on the reactive &lt;code&gt;$state&lt;/code&gt;, which instantly repaints the entire interface when the language changes, without resetting any unsaved changes on the carousel canvas:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/lib/i18n/i18n.svelte.ts&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;I18nService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;locale&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;$state&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;uk&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Reactive language state&lt;/span&gt;

    &lt;span class="nf"&gt;t&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&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;translations&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;locale&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nf"&gt;setLocale&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newLocale&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;locale&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;newLocale&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;smm_lang&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;newLocale&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;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;i18n&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;I18nService&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Because &lt;code&gt;locale&lt;/code&gt; is a &lt;code&gt;$state&lt;/code&gt;, any component using &lt;code&gt;i18n.t('key')&lt;/code&gt; will instantly update as soon as the language changes. This also made it painless to set up automatic language detection: if a person enters the editor from an English or German browser, the script immediately reads &lt;code&gt;navigator.language&lt;/code&gt; and automatically turns on the English version of the interface.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fshcho-i-yak.pp.ua%2Fimages%2Fuploads%2Fsmm-turbo-i18n-runes.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fshcho-i-yak.pp.ua%2Fimages%2Fuploads%2Fsmm-turbo-i18n-runes.webp" title="Implementation of reactive multilingualism using Svelte 5 runes" alt="Svelte 5 localization service code" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  🪄 AI Magic: In-Browser background removal
&lt;/h2&gt;

&lt;p&gt;A cool graphic editor for creating Instagram carousels in 2026 can't exist without built-in artificial intelligence. &lt;/p&gt;

&lt;p&gt;Usually, services ask for money for background removal, because they send your photo to remote powerful servers with GPU. I decided to make this process local and free!&lt;/p&gt;

&lt;p&gt;I used the incredible &lt;code&gt;@imgly/background-removal&lt;/code&gt; library. This is a real revolution! The neural network is loaded in WebAssembly (WASM) format directly into your browser.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&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;handleRemoveBackground&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;isRemovingBg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;imgly&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@imgly/background-removal&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;removeBg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;imgly&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;removeBackground&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="c1"&gt;// AI works directly on the user's device&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;imageBlob&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;removeBg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;selected&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;content&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;imageBlob&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="nx"&gt;selected&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;content&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;editor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;saveState&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Failed to remove background.&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;span class="k"&gt;finally&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;isRemovingBg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You just select a photo, click the "Remove Background" button, and your computer perfectly cuts out the main object in a couple of seconds. No limits, subscriptions, or transferring confidential photos to third-party servers.&lt;/p&gt;

&lt;h2&gt;
  
  
  🤖 AI Co-Pilot based on Llama 3.1
&lt;/h2&gt;

&lt;p&gt;In addition to working with images, I added a text AI assistant. A special purple button with a star ✨ at the bottom of the screen invokes the &lt;strong&gt;AI Co-Pilot&lt;/strong&gt; panel. It works through the ultra-fast API from &lt;strong&gt;Groq&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;To make the AI respond instantly and always in the correct format, I created a separate API route on the server (&lt;code&gt;+server.ts&lt;/code&gt;). Here's the real backend code that's responsible for the magic of generating texts:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&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;json&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;@sveltejs/kit&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;Groq&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;groq-sdk&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;GROQ_API_KEY&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;$env/static/private&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;groq&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;Groq&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;apiKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;GROQ_API_KEY&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;POST&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;request&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;mode&lt;/span&gt; &lt;span class="p"&gt;}&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;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&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;systemMessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;;&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;mode&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;canvas&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;span class="nx"&gt;systemMessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`You are a creative copywriter. 
The user will ask you to come up with text. Provide exactly 3 short and catchy options. 
Format your response so that each option starts with a new line and the symbol 🔹. 
No introductory words! Language: English.`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; 
    &lt;span class="c1"&gt;// ... other modes (Alchemist, Artist)&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;chatCompletion&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;groq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;completions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;messages&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="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;system&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;systemMessage&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;prompt&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;llama-3.1-8b-instant&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;temperature&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;max_tokens&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1024&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="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;result&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;chatCompletion&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;choices&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;message&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;content&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;Here, I implemented 3 modes:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;🧙‍♂️ &lt;strong&gt;Alchemist:&lt;/strong&gt; Transforms a short idea into a detailed professional prompt for ChatGPT or Claude.&lt;/li&gt;
&lt;li&gt;🎨 &lt;strong&gt;Artist:&lt;/strong&gt; Helps generate detailed English-language requests for Midjourney.&lt;/li&gt;
&lt;li&gt;💬 &lt;strong&gt;On canvas:&lt;/strong&gt; The coolest feature! You ask to come up with a clickbait headline, AI gives you 3 options, and you can add the selected text directly to the current slide of the carousel with one click (&lt;code&gt;+ On slide&lt;/code&gt;).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fshcho-i-yak.pp.ua%2Fimages%2Fuploads%2Fsmm-turbo-ai-copilot.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fshcho-i-yak.pp.ua%2Fimages%2Fuploads%2Fsmm-turbo-ai-copilot.webp" title="AI Co-Pilot interface: generating clickable headlines for the carousel using Llama 3.1" alt="AI Co-Pilot in action within the editor" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  🔄 State Management: Svelte 5 Magic
&lt;/h2&gt;

&lt;p&gt;One of the biggest challenges in developing a graphic editor is state management (State Management). We need to store the position of each element, manage the active slide, and implement the undo/redo function.&lt;/p&gt;

&lt;p&gt;Thanks to the new runes in Svelte 5 (&lt;code&gt;$state&lt;/code&gt;), creating such a global storage has become incredibly elegant. I created a &lt;code&gt;state.svelte.ts&lt;/code&gt; file, where I described the &lt;code&gt;editor&lt;/code&gt; object:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;createEditorState&lt;/span&gt;&lt;span class="p"&gt;()&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;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;$state&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;carousel&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;canvasFormat&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1:1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;currentSlides&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="na"&gt;elements&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt; &lt;span class="na"&gt;backgroundOverlay&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="na"&gt;activeSlideIndex&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="na"&gt;selectedId&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="na"&gt;history&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
        &lt;span class="na"&gt;historyIndex&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&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;get&lt;/span&gt; &lt;span class="nf"&gt;activeSlide&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;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;currentSlides&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;activeSlideIndex&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;

        &lt;span class="nf"&gt;saveState&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// Logic for saving steps for Undo/Redo&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;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;historyIndex&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;history&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;history&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;history&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="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;historyIndex&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;history&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;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;currentSlides&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
            &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;historyIndex&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;

        &lt;span class="nf"&gt;undo&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&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;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;historyIndex&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="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;historyIndex&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;currentSlides&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;history&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;historyIndex&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="p"&gt;});&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;editor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createEditorState&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every time an element's coordinates change (Drag &amp;amp; Drop), &lt;code&gt;editor.saveState()&lt;/code&gt; is called, which adds a new snapshot of the data to the history array. Now the user can safely press &lt;code&gt;Ctrl+Z&lt;/code&gt;, and the system will instantly revert the changes.&lt;/p&gt;

&lt;h2&gt;
  
  
  📦 Storage and Integration with Stocks
&lt;/h2&gt;

&lt;p&gt;So that users don't lose their masterpieces after closing the tab, I connected a backend based on &lt;strong&gt;Supabase&lt;/strong&gt; (PostgreSQL + Auth + Storage). &lt;/p&gt;

&lt;p&gt;Authorization takes a few seconds. After that, all your projects are automatically saved to the cloud database. To upload your own images, I use &lt;em&gt;Supabase Storage&lt;/em&gt;, generating unique file names so they don't overwrite each other.&lt;/p&gt;

&lt;p&gt;I also integrated the free photo stock &lt;strong&gt;Pixabay&lt;/strong&gt;. The user can directly in the editor enter a search query in English (e.g., &lt;em&gt;dark space, aesthetic coffee&lt;/em&gt;), get a grid of results through the Pixabay API, and with one click set the image as the slide background or add it as a separate element.&lt;/p&gt;

&lt;h2&gt;
  
  
  🏁 Conclusion
&lt;/h2&gt;

&lt;p&gt;Creating your own technical product is always a challenge, but it's an incredible experience. &lt;strong&gt;SMM Turbo&lt;/strong&gt; grew from a simple idea for personal needs into a full-fledged &lt;strong&gt;graphic editor for creating Instagram carousels&lt;/strong&gt;, capable of closing 90% of a marketer's or developer's daily tasks.&lt;/p&gt;

&lt;p&gt;A lightning-fast interface on Svelte 5, powerful artificial intelligence "under the hood", seamless background removal, and complete freedom of action (without annoying watermarks or limits) make it a great alternative to paid monopolists.&lt;/p&gt;

&lt;h2&gt;
  
  
  🔥 &lt;strong&gt;Want to try this magic for yourself?&lt;/strong&gt; My editor is completely free and already available for testing.
&lt;/h2&gt;

&lt;h3&gt;
  
  
  🚀 Try SMM Turbo right now
&lt;/h3&gt;

&lt;p&gt;No subscriptions, payments, or hidden fees. Built for creators.&lt;br&gt;
👉 &lt;strong&gt;&lt;a href="https://smm.shcho-i-yak.pp.ua" rel="noopener noreferrer"&gt;Open SMM Turbo Editor (Free)&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;




</description>
      <category>showdev</category>
      <category>svelte</category>
      <category>webdev</category>
      <category>ai</category>
    </item>
  </channel>
</rss>
