<?xml version="1.0" encoding="UTF-8"?><?xml-stylesheet href="/scripts/pretty-feed-v3.xsl" type="text/xsl"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:h="http://www.w3.org/TR/html4/"><channel><title>Norb&apos;s Space</title><description>Where knowledge and ideas flow.</description><link>https://astro-pure.js.org</link><item><title>Simply Nord</title><link>https://astro-pure.js.org/blog/simply-nord</link><guid isPermaLink="true">https://astro-pure.js.org/blog/simply-nord</guid><description>Building a beautiful, minimalistic theme for KDE Plasma 6.</description><pubDate>Thu, 19 Feb 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Two weeks ago I decided to make the switch from Windows to Arch Linux. When selecting a desktop environment, I found myself choosing between KDE Plasma and GNOME. Having used GNOME before, I decided to give KDE Plasma a try, since I have heard that it is highly customizable.&lt;/p&gt;
&lt;p&gt;I like KDE Plasma for its clean interface and powerful customization options, but the default theme seems less modern compared to the polished and unified look of GNOME. Therefore I decided to remix my own theme for KDE Plasma, based on the popular Nord color palette.&lt;/p&gt;
&lt;p&gt;Technically, &lt;em&gt;Simply Nord&lt;/em&gt; is not a theme, but rather a collection of themes, kwin scripts, widgets, panels and many more customizations, all combined to provide a beautiful, minimalistic desktop experience. I drew inspiration from GNOME, Dank Material Theme, and multiple desktop designs, recreating a keyboard-driven workflow that blends productivity and aesthetics.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://astro-pure.js.org/_image?href=%2F_astro%2Fdesktop.CuVo6_j3.jpg&amp;#x26;w=3200&amp;#x26;h=2000&amp;#x26;f=webp&quot; alt=&quot;desktop&quot;&gt;&lt;/p&gt;
&lt;p&gt;{{ Figure 1: Screenshot from the Simply Nord Theme. }}&lt;/p&gt;
&lt;p&gt;In this blog post, I will share the process of creating &lt;em&gt;Simply Nord&lt;/em&gt;, so that you can easily set it up on your KDE Plasma desktop.&lt;/p&gt;
&lt;h2&gt;Designing the Workflow&lt;/h2&gt;
&lt;p&gt;Looks are important, but what is more important is the &lt;strong&gt;workflow&lt;/strong&gt; behind the design. It is always important to take a while to think about how you &lt;strong&gt;wish to access&lt;/strong&gt; the myriad of applications and actions provided by the desktop environment. Think about how you want to launch applications, access opened windows, switch between workspaces, and so on. Be consistent in your design, and use your desired workflow to guide your design decisions.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;workflow-light.svg&quot; alt=&quot;workflow&quot;&gt;&lt;img src=&quot;workflow-dark.svg&quot; alt=&quot;workflow&quot;&gt;&lt;/p&gt;
&lt;p&gt;{{ Figure 2: The workflow diagram of the Simply Nord Theme. }}&lt;/p&gt;
&lt;p&gt;For &lt;em&gt;Simply Nord&lt;/em&gt;, the workflow I chose is aggressively keyboard-driven. I got rid of the task manager altogether, and chose to rely on KRunner to launch applications and the Window Switcher to switch between opened windows. I work on a laptop, and frequently do not use a mouse, so I extended the touchpad gestures. I use three-finger swipes to open the Overview Effect, and four-finger swipes to switch between workspaces. The strong emphasis on keyboard and touchpad navigation allowed me to create a clean and minimalistic desktop.&lt;/p&gt;
&lt;p&gt;If you are interested in adopting the theme, but are uncomfortable with a keyboard-driven workflow, you should consider adding a task manager and modifying the shortkeys to your liking. This is the primary reason why I chose to produce a blog tutorial instead of a ready-to-use, drop-and-go konsave archive.&lt;/p&gt;
&lt;h2&gt;First Things First: Backup Your Theme&lt;/h2&gt;
&lt;p&gt;Before you start modifying your desktop, it is always a good idea to make a backup of your current configuration. The latest edition of KDE Plasma already provides built-in support for exporting and importing desktop configurations, but for complex setups like this I prefer to use &lt;a href=&quot;http://github.com/Prayag2/konsave&quot;&gt;Konsave&lt;/a&gt; since it is more flexible.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;konsave --save kde-standard
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After this, you should be ready to start modifying your desktop. You can always restore the backup using the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;konsave --apply kde-standard
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Playing with Panels&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;https://astro-pure.js.org/_image?href=%2F_astro%2Fpanels.QVw6pBsr.jpg&amp;#x26;w=3199&amp;#x26;h=1770&amp;#x26;f=webp&quot; alt=&quot;panels&quot;&gt;&lt;/p&gt;
&lt;p&gt;In KDE Plasma, the default panel closely resembles the Windows taskbar. It spans the entire width of the screen and contains primarily a task manager as well as the system tray. Classic design as it is, it does not fit the modern and minimalistic look I was going for. Therefore, I moved the panel to the top of the screen, and turned it into a top bar. You can do so by right-clicking on the panel, selecting &lt;em&gt;Show Panel Configuration&lt;/em&gt; and modifying the settings to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Position: Top&lt;/li&gt;
&lt;li&gt;Visibility: Always Visible&lt;/li&gt;
&lt;li&gt;Floating: Disabled&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The last two configuration options disable the &quot;hiding&quot; behavior of the panel, making it always visible. The default panel is a bit too thick, so I reduced the height to 25 pixels.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;top-bar-light.svg&quot; alt=&quot;top-bar&quot;&gt;&lt;img src=&quot;top-bar-dark.svg&quot; alt=&quot;top-bar&quot;&gt;&lt;/p&gt;
&lt;p&gt;As for widgets, I removed the task manager and displayed the time in the center, using &lt;code&gt;ddd d MMM,&lt;/code&gt; to display the date besides the time within the same line. The leftside &lt;code&gt;Toggle Overview&lt;/code&gt; button is from the &lt;a href=&quot;https://store.kde.org/p/2132554&quot;&gt;KDE Store&lt;/a&gt; with a custom icon.&lt;/p&gt;
&lt;h3&gt;Addressing the Animation Issue&lt;/h3&gt;
&lt;p&gt;One issue I encountered is that, after removing all task managers from the screen, the &lt;code&gt;Squash&lt;/code&gt; animation for minimizing windows stops working. I have reported this as a &lt;a href=&quot;https://bugs.kde.org/show_bug.cgi?id=516180&quot;&gt;bug&lt;/a&gt;, and hopefully in a future update this will be fixed.&lt;/p&gt;
&lt;p&gt;In the meantime, you can use &lt;a href=&quot;https://github.com/RayZh-hs/Squash-Plus/&quot;&gt;my fork of Squash Plus&lt;/a&gt; which provides a &quot;Minimize To&quot; configuration option. You can set this to any of the fixed positions on the screen, which fixes this issue.&lt;/p&gt;
&lt;p&gt;In my case, I set it to the top left corner, which is where the &lt;code&gt;Toggle Overview&lt;/code&gt; button is located, and where the magic corner is set to toggle the overview too. This way it seems that windows are minimized to the Overview screen, which makes for consistency in the design.&lt;/p&gt;
&lt;h2&gt;Hotkeys and Touchpad Gestures&lt;/h2&gt;
&lt;p&gt;KDE Desktop provides a powerful system for configuring hotkeys under the &quot;Keyboard &gt; Shortcuts&quot; settings. The configuration I am using:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Alt + Space&lt;/code&gt;: Open KRunner&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Alt + F4&lt;/code&gt;: &lt;a href=&quot;https://store.kde.org/p/2138867&quot;&gt;Close Window or Log Out&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Meta + E&lt;/code&gt;: Open Dolphin&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Meta + C&lt;/code&gt;: Open Chrome&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Meta + K&lt;/code&gt;: Open Konsole&lt;/li&gt;
&lt;li&gt;Additional KWin Script: Geometry Change&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;However, the almighty KDE Plasma seems to be in surprising lack of touchpad customization options. To solve this issue I resorted to using &lt;a href=&quot;https://github.com/taj-ny/InputActions&quot;&gt;Input Actions&lt;/a&gt;, a community-developed tool that provides cross-desktop support for input device triggers. Here is the script I am using to configure the touchpad gestures:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;touchpad:
  gestures:
    # Three-finger swipe to cycle between tabs
    - type: swipe
      fingers: 3
      direction: left_right
      actions:
        # 1. Start: Hold Alt and tap Tab once to open the menu
        - on: begin
          input:
            - keyboard: [ +leftalt, tab ]

        # 2. Moving Left: Cycle backwards (Shift+Tab)
        - on: update
          interval: -75
          input:
            - keyboard: [ leftshift+tab ]

        # 3. Moving Right: Cycle forwards (Tab)
        - on: update
          interval: 75
          input:
            - keyboard: [ tab ]

        # 4. End: Release Alt to select the window
        - on: end
          input:
            - keyboard: [ -leftalt ]

        # 5. Cancel: Release Alt if gesture is interrupted
        - on: cancel
          input:
            - keyboard: [ -leftalt ]

    # 3 Fingers Up -&gt; Spreadsheet View (Desktop Grid)
    - type: swipe
      fingers: 3
      direction: up
      actions:
        - on: begin
          input:
            - keyboard: [ leftmeta+w ]

    # Wait for 3 finger down to exit spreadsheet view
    - type: swipe
      fingers: 3
      direction: down
      actions:
        - on: begin
          input:
            - keyboard: [ leftmeta+w ]

    # 4 Fingers Up -&gt; Task View (Desktop Grid)
    - type: swipe
      fingers: 4
      direction: up
      actions:
        - on: begin
          input:
            - keyboard: [ leftmeta+g ]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This configuration modifies the three-finger swipe to open the Overview Effect, and the four-finger swipe to switch between workspaces. You can modify the configuration to your liking, and add more gestures if you wish.&lt;/p&gt;
&lt;h2&gt;Color Theme Support&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;Light attracts bugs. Dark attracts developers.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I set out by browsing the KDE Store for &lt;a href=&quot;https://www.nordtheme.com/&quot;&gt;Nord&lt;/a&gt; color schemes. Several options are available, but I ended up choosing &lt;a href=&quot;https://store.kde.org/p/1801641&quot;&gt;Nordic Bluish KDE&lt;/a&gt; theme for most setups:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Colors: Nordic Bluish&lt;/li&gt;
&lt;li&gt;Application Style: Kvantum (I will cover this later)&lt;/li&gt;
&lt;li&gt;Plasma Style: Nordic Bluish&lt;/li&gt;
&lt;li&gt;Window Decorations: Nordic&lt;/li&gt;
&lt;li&gt;Icons: Breeze Dark (See more in &lt;a href=&quot;#icons&quot;&gt;Icons&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Cursors: Nordic-Cursors&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Compared with builtin color theme support, I prefer to use &lt;a href=&quot;https://github.com/tsujan/Kvantum&quot;&gt;Kvantum&lt;/a&gt; to provide better support for qt applications, since it comes with enhanced flexibility and capability. &lt;a href=&quot;https://github.com/HimDek/Utterly-Nord-Plasma&quot;&gt;Utterly Nord Plasma&lt;/a&gt; is a qt theme with great support for acrylic and blur effects, and is the one I am using for &lt;em&gt;Simply Nord&lt;/em&gt;. I especially like its dropdown menu design, which is brings out the subtle use of colors in the Nord palette.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://astro-pure.js.org/_image?href=%2F_astro%2Fdropdown-menu.TFywa2YJ.png&amp;#x26;w=1579&amp;#x26;h=1085&amp;#x26;f=webp&quot; alt=&quot;dropdown-menu&quot;&gt;&lt;/p&gt;
&lt;p&gt;Ensure that you have &quot;Blur&quot; enabled in &quot;Desktop Effects&quot; settings. It should be pointed out that that the default Utterly Nord Plasma theme is rather aggressively transparent, which makes some windows such as Kate and Dolphin look weird on light backgrounds. The workaround I found is to use the &quot;Kvantum Solid&quot; variation of the theme and, under Application Themes, apply it to windows that are frequently moved above light backgrounds with the &quot;Application Themes&quot; section in Kvantum.&lt;/p&gt;
&lt;p&gt;Another tip: I found that the Nordic Bluish color scheme in Dolphin is a bit unclear. The solution is to &quot;Settings &gt; Configure &gt; Window Color Scheme&quot; and use another. I strongly recommend &lt;a href=&quot;https://store.kde.org/p/1633673&quot;&gt;Nordic Darker&lt;/a&gt;, which looks crisp and clear with the default white Breeze Icons.&lt;/p&gt;
&lt;h2&gt;Wallpaper and Screens&lt;/h2&gt;
&lt;p&gt;The wallpaper that I am using comes from a &lt;a href=&quot;https://www.reddit.com/r/wallpaper/comments/106xrta/1920x1080_nordic_mountains/&quot;&gt;Reddit post&lt;/a&gt;. It should be noted that for some reason the image you download from the post is of 4717×2984 resolution despite it being said to be 1920×1080. For best quality you can downscale it to 1080p and then upscale it back to 4K using a tool like &lt;a href=&quot;https://github.com/upscayl/upscayl&quot;&gt;Upscayl&lt;/a&gt;. This will significantly reduce blur. Or, simply click the link below to download the wallpaper that I upscaled:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/download/simply-nord-wallpaper-4x.png&quot; title=&quot;attachment&quot;&gt;Upscaled Wallpaper&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Remember to set the wallpaper in &lt;strong&gt;two places&lt;/strong&gt;: the &quot;Login Screen (SDDM)&quot; and the &quot;Screen Locking&quot; settings. Set both to &quot;Breeze&quot; and use the configuration button to set the wallpaper to the one you downloaded.&lt;/p&gt;
&lt;h2&gt;Icons&lt;/h2&gt;
&lt;p&gt;Icons are arguably the hardest part to configure in a typical KDE Plasma desktop. Many of the icon sets that I found seem to be incomplete, and using them leads to visual inconsistencies. Therefore, I settled on using the default Breeze Dark icons as the base, and building icon overrides across applications.&lt;/p&gt;
&lt;p&gt;It turns out that KRunner has a dedicated &lt;code&gt;~/.config/krunnerrc&lt;/code&gt; configuration file, where you can specify icon sets to use for KRunner specifically. For the nord theme, both &lt;a href=&quot;https://github.com/zayronxio/Zafiro-icons&quot;&gt;Zafiro Icons&lt;/a&gt; and its fork &lt;a href=&quot;https://github.com/zayronxio/Zafiro-Nord-Dark&quot;&gt;Zafiro Nord Dark&lt;/a&gt; works perfectly. You can use them by cloning them (or cloning and copying the &lt;code&gt;Dark&lt;/code&gt; folder) into &lt;code&gt;~/.local/share/icons/&lt;/code&gt; and setting:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[Icons]
Theme=Zafiro-Nord-Dark
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;However, I noticed that both icon sets modify the top search bar of KRunner, which I dislike. To resolve this issue, we will build a custom icon set that inherits the zafiro icons but overrides the search bar icons.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://astro-pure.js.org/_image?href=%2F_astro%2Fkrunner.CE3bADzJ.png&amp;#x26;w=2042&amp;#x26;h=1163&amp;#x26;f=webp&quot; alt=&quot;krunner&quot;&gt;
{{ Figure 3: The KRunner with modified Zafiro Icon Set. }}&lt;/p&gt;
&lt;p&gt;To this end, we would first need to figure out the names of these icons used. This is surprisingly difficult, since I have not found any builtin tool in KDE Plasma to inspect icons. After much research, I found &lt;a href=&quot;https://github.com/etherfield/breeze-icons-debug&quot;&gt;Breeze Icons Debug&lt;/a&gt; by etherfield, an icon set that replaces all icons with an image consisting of the icon id. This allowed me to easily identify the icons used in the KRunner search bar, and I built this custom icon set:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot;&gt;~/.local/share/icons/KRunner-Icons-Override
├── actions
│   ├── 24
│   │   ├── edit-clear-locationbar-rtl.svg
│   │   └── search.svg
│   └── 48
│       ├── configure.svg
│       ├── expand.svg
│       ├── question.svg
│       └── window-pin.svg
├── append
└── index.theme
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;index.theme&lt;/code&gt; file is as follows:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ini&quot;&gt;[Icon Theme]
Name=Simply Nord: KRunner Icons Override
Comment=KRunner override icons for theme Simply Nord
Inherits=Zafiro-Nord-Dark,breeze-dark

Directories=actions/24,actions/48

[actions/24]
Size=24
Context=Actions
Type=Fixed

[actions/48]
Size=48
Context=Actions
Type=Fixed
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the directories, I copied icons sampled from the Breeze Dark icon set. I will provide the python I used to extract these icons and follow symbolic links:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/download/icon-append.py&quot; title=&quot;attachment&quot;&gt;Python Script for Icon Extraction &amp;#x26; Append&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;As you have seen in Image 3, the search bar icons are now overridden to match the Breeze Dark icons, while the rest of the KRunner icons are inherited from the Zafiro Nord Dark icon set. The result is a vastly more consistent and polished look for KRunner.&lt;/p&gt;
&lt;p&gt;Similarly, you can override the folder icons in Dolphin to adjust the colored folders to match the Nord palette.&lt;/p&gt;
&lt;h2&gt;Final Touch: Fonts&lt;/h2&gt;
&lt;p&gt;Fonts matter. People often complain about the default fonts in Linux look ... well, a bit outdated, but this problem is absolutely solvable. First, install fonts of your choice. I am using &lt;a href=&quot;https://www.google.com/get/noto/&quot;&gt;Noto Sans&lt;/a&gt; for user interface, and &lt;a href=&quot;https://www.jetbrains.com/lp/mono/&quot;&gt;JetBrains Mono&lt;/a&gt; for monospace usage like in terminals. When it comes to Asian typography, &lt;a href=&quot;https://source.typekit.com/source-han-serif/&quot;&gt;Source Hans Serif&lt;/a&gt; is my primary choice for documents.&lt;/p&gt;
&lt;p&gt;Change the font in the digital clock in the top bar to 8pt Noto Sans. See how much that affects the overall feel of the desktop? We consider fonts as the final touch to the desktop configuration, since they make up much of the micro-details that make the desktop brilliant.&lt;/p&gt;
&lt;p&gt;Font management in linux can be tricky, since what you ask for is not always what you get. For example, the famous &quot;Arial&quot; font is actually replaced by &quot;Liberation Sans&quot; in most Linux distributions.&lt;/p&gt;
&lt;p&gt;For me, I noticed that the default font system used &quot;FreeSans&quot; for symbol glyphs, which led to issues where the arrow symbol is not vertically centered and so on. Whenever you encounter such issues, you can use the &lt;code&gt;fontconfig&lt;/code&gt; system to set up font fallbacks and overrides.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;fc-match -s &quot;sans-serif:charset=2192&quot; | head
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will show you the font fallback chain for the arrow symbol (modify 2192 to the codepoint of the symbol you are looking up). To resolve such issues, create your own configuration files in &lt;code&gt;~/.config/fontconfig/conf.d/&lt;/code&gt; and specify font fallback rules. One trick that I found was that in most circusmstances, Noto Sans Symbols seemed to have better glyph design.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-xml&quot;&gt;&amp;#x3C;?xml version=&apos;1.0&apos;?&gt;
&amp;#x3C;!DOCTYPE fontconfig SYSTEM &apos;urn:fontconfig:fonts.dtd&apos;&gt;
&amp;#x3C;fontconfig&gt;
 &amp;#x3C;!-- Strip Noto Sans Symbols of Latin characters --&gt;
 &amp;#x3C;match target=&quot;scan&quot;&gt;
  &amp;#x3C;test name=&quot;family&quot;&gt;
   &amp;#x3C;string&gt;Noto Sans Symbols&amp;#x3C;/string&gt;
  &amp;#x3C;/test&gt;
  &amp;#x3C;edit mode=&quot;assign&quot; name=&quot;charset&quot;&gt;
   &amp;#x3C;minus&gt;
    &amp;#x3C;name&gt;charset&amp;#x3C;/name&gt;
    &amp;#x3C;charset&gt;
     &amp;#x3C;range&gt;
      &amp;#x3C;int&gt;0x0030&amp;#x3C;/int&gt;
      &amp;#x3C;int&gt;0x0039&amp;#x3C;/int&gt;
     &amp;#x3C;/range&gt;
     &amp;#x3C;!-- 0-9 --&gt;
     &amp;#x3C;range&gt;
      &amp;#x3C;int&gt;0x0041&amp;#x3C;/int&gt;
      &amp;#x3C;int&gt;0x005A&amp;#x3C;/int&gt;
     &amp;#x3C;/range&gt;
     &amp;#x3C;!-- A-Z --&gt;
     &amp;#x3C;range&gt;
      &amp;#x3C;int&gt;0x0061&amp;#x3C;/int&gt;
      &amp;#x3C;int&gt;0x007A&amp;#x3C;/int&gt;
     &amp;#x3C;/range&gt;
     &amp;#x3C;!-- a-z --&gt;
    &amp;#x3C;/charset&gt;
   &amp;#x3C;/minus&gt;
  &amp;#x3C;/edit&gt;
 &amp;#x3C;/match&gt;
 &amp;#x3C;!-- When querying sans-serif fonts, resort to Noto Sans Symbols for symbols --&gt;
 &amp;#x3C;match target=&quot;pattern&quot;&gt;
  &amp;#x3C;test name=&quot;family&quot; qual=&quot;any&quot;&gt;
   &amp;#x3C;string&gt;Arial&amp;#x3C;/string&gt;
  &amp;#x3C;/test&gt;
  &amp;#x3C;edit binding=&quot;strong&quot; mode=&quot;prepend&quot; name=&quot;family&quot;&gt;
   &amp;#x3C;string&gt;Noto Sans Symbols&amp;#x3C;/string&gt;
  &amp;#x3C;/edit&gt;
 &amp;#x3C;/match&gt;
 &amp;#x3C;match target=&quot;pattern&quot;&gt;
  &amp;#x3C;test name=&quot;family&quot; qual=&quot;any&quot;&gt;
   &amp;#x3C;string&gt;Roboto&amp;#x3C;/string&gt;
  &amp;#x3C;/test&gt;
  &amp;#x3C;edit binding=&quot;strong&quot; mode=&quot;prepend&quot; name=&quot;family&quot;&gt;
   &amp;#x3C;string&gt;Noto Sans Symbols&amp;#x3C;/string&gt;
  &amp;#x3C;/edit&gt;
 &amp;#x3C;/match&gt;
 &amp;#x3C;match target=&quot;pattern&quot;&gt;
  &amp;#x3C;test name=&quot;family&quot; qual=&quot;any&quot;&gt;
   &amp;#x3C;string&gt;sans-serif&amp;#x3C;/string&gt;
  &amp;#x3C;/test&gt;
  &amp;#x3C;edit binding=&quot;strong&quot; mode=&quot;prepend&quot; name=&quot;family&quot;&gt;
   &amp;#x3C;string&gt;Noto Sans Symbols&amp;#x3C;/string&gt;
  &amp;#x3C;/edit&gt;
 &amp;#x3C;/match&gt;
 &amp;#x3C;dir&gt;~/.local/share/fonts&amp;#x3C;/dir&gt;
&amp;#x3C;/fontconfig&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This script effectively applys Noto Sans Symbols as the fallback font for all sans-serif symbol fonts. We need to strip Noto Sans Symbols of Latin characters since it contains such a sample sequence, which will otherwise take precedence over fonts the browser queries for letters.&lt;/p&gt;
&lt;p&gt;Each time you modify the font configuration, make sure to clear the font cache:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;fc-cache -f
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Take some time to experiment with fonts in all your applications, and make sure that each modification you make does not introduce new issues in font rendering. This will help you achieve a consistent and polished look across your desktop.&lt;/p&gt;
&lt;p&gt;That&apos;s all! When you are done, you should have a beautiful, minimalistic KDE Plasma desktop ready to go. Happy theming!&lt;/p&gt;</content:encoded><h:img src="/_astro/thumbnail.xN6SHI3V.jpg"/><enclosure url="/_astro/thumbnail.xN6SHI3V.jpg"/></item><item><title>Getting Modular</title><link>https://astro-pure.js.org/blog/getting-modular</link><guid isPermaLink="true">https://astro-pure.js.org/blog/getting-modular</guid><description>Design notes on mango submodules.</description><pubDate>Thu, 30 Oct 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;https://github.com/Mango-CLI/Mango&lt;/p&gt;
&lt;h2&gt;TL;DR&lt;/h2&gt;
&lt;p&gt;Mango has got submodule support at last. Update, and enjoy.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;What This Blog is About&lt;/h2&gt;
&lt;p&gt;If you are seeking information about the recent submodule update, or wish to learn how to use it, you can utilize the new builtin &lt;code&gt;mango @help&lt;/code&gt; command to look up detailed information about all commands.&lt;/p&gt;
&lt;p&gt;If you wish to develop your own templates and submodules, you will find documentation in the README.md file, and a multitude of demo templates in the &lt;a href=&quot;https://github.com/Mango-CLI/builtins.mango&quot;&gt;builtins repo&lt;/a&gt; should serve as a great starting point. A detailed online documentation entailing all mango features is planned, as will be released soon.&lt;/p&gt;
&lt;p&gt;So why am I writing this blog?&lt;/p&gt;
&lt;p&gt;The simple answer is, I wish to document the process I went through designing submodules and templates for Mango. &lt;strong&gt;Each step of design, each choice taken or reverted bear careful analysis and reasoning.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;So this blog is not going to be a detailed tour on how to use submodules. Instead, it will guide you through a journey behind and beyond the mango submodule system you see now. If you want to dive deeper, and truly understand modularity in mango, you have come to the right place. If it so happens that you want to introduce modularity or reusability to one of your brilliant projects, you may also find some inspiration here.&lt;/p&gt;
&lt;p&gt;So sit back, and let&apos;s begin.&lt;/p&gt;
&lt;h2&gt;Craving Modularity&lt;/h2&gt;
&lt;p&gt;For me, one common use case of Mango is managing my schoolwork. Most of the time we rely on the famous Canvas Infrastructure, and I found myself repeatedly downloading assignments, doing them locally, and uploading them back. Mango helps me automate this process.&lt;/p&gt;
&lt;p&gt;The problem is, different courses have different requirements, and I had to write the same canvas-handling code over and over again, which is tedious and annoying. I wished for a method to reuse the code across different mango repos.&lt;/p&gt;
&lt;p&gt;Another point that I came across is that, in the old mango system, there is no good way to update the mango builtin commands. Users are free to roam the home repo and modify any file. In fact, they are encouraged to tailor their home mango to fit their own needs. Yet, this freedom comes at a cost: there is no way to systematically update the home repo, as rebooting the home repo will remove all user-defined scripts within.&lt;/p&gt;
&lt;p&gt;Mango prides itself on being an extremely lightweight yet flexible script manager, yet the simplicity of the old mango system has placed a limit on its extensibility. &lt;strong&gt;A simple, tiled script layout is easy to understand, but hard to extend.&lt;/strong&gt; There was in truth no good way to manage dependencies between scripts, or to publish reusable code.&lt;/p&gt;
&lt;h2&gt;A Vague Idea&lt;/h2&gt;
&lt;p&gt;So I started by asking myself:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;What does modularity mean to Mango? What should it look like?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The first question is easy to answer: I want to incorporate a selection of &quot;reusable code&quot; from other repos, or other creators, into my own mango repo. This reusable code is either a dependency for my own code, or a set of commands that I want to use directly in this context. Unlike my own commands, such a segment should instead be &lt;strong&gt;externally maintained, and easily updatable&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;The second question is trickier. There were lots of possible designs. What should submodules be? Should they be a a script that enacts a side effect on the mango repo? Or a archive that follows some given convention designed to provide functionality to the repo? How can the user access this reusable codebase? How should submodules be managed and updated?&lt;/p&gt;
&lt;p&gt;There is no end to the questions to be answered, so I started out by investigating existing modularity systems.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Git Submodules: Git allows users to include other git repos as subdirectories of their own repo. They can &quot;clone&quot; others&apos; repos directly into their own, facilitating code reuse. There is no &quot;central hub&quot; for git submodules, and users manage submodules per project. Git keeps track of submodules and their versions in a special &lt;code&gt;.gitmodules&lt;/code&gt; file.&lt;/li&gt;
&lt;li&gt;Linux Package Managers: Most linux systems ship with package managers, which provide a unified method to extend the os with third party software. Packages are served from central repositories, and are locally bookmarked strictly by name and version. They are installed in autonomous directories, and exposed to the user via binaries in the system PATH.&lt;/li&gt;
&lt;li&gt;Vim Extensions: Vim has a rich ecosystem of extensions, and numerous famous extension managers. Extensions are usually placed in a special directory. Their functionality comes from following directory structures.&lt;/li&gt;
&lt;li&gt;Python packages: Python also uses naming conventions and directory structures to define packages. They can be installed from central repositories, or can be user-defined.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So the problem boils down to several key design choices:&lt;/p&gt;
&lt;blockquote&gt;
&lt;ol&gt;
&lt;li&gt;Is there a central repository for submodules, or is it decentralized?&lt;/li&gt;
&lt;li&gt;What format should a submodule take?&lt;/li&gt;
&lt;li&gt;Where should submodules be installed? In a central directory, or scattered project-wise? If the latter is true, how can we keep track of them?&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;p&gt;The first question is simple. The topmost merit of having a central repository is security. However, it places a great limit on the freedom of publishers. Mango, as a user-driven script management tool, should make it easy for users to create and share content. &lt;strong&gt;Users should decide what they trust and what to use in their own mango repos.&lt;/strong&gt; Therefore, I decided to go with a decentralized design. (Besides, I do not have the resources to maintain a central repository.)&lt;/p&gt;
&lt;p&gt;The second question I found inspiration from git. Any git repo can be a submodule, which creates an isomorphism between git submodules and git repos. This is great design, as it allows for greater flexibility, as well as minimal workload for the developer to translate existing repos into submodules.&lt;/p&gt;
&lt;p&gt;The last problem is indeed the trickiest. After much deliberation, I decided to go with a project-wise submodule system, since versioning may vary from project to project. Yet I found it pretty hard to decide on a single design. Here are some ideas put forward during the design process:&lt;/p&gt;
&lt;p&gt;Regarding the construct of submodules:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The git repo itself is the &lt;code&gt;.mango&lt;/code&gt; folder renamed. It contains &lt;code&gt;.instructions&lt;/code&gt; and all other files.&lt;/li&gt;
&lt;li&gt;The git repo wraps around the &lt;code&gt;.mango&lt;/code&gt; folder, so &lt;code&gt;.git&lt;/code&gt; and &lt;code&gt;.mango&lt;/code&gt; are parallel directories. This enables users to place other files outside the mango implementation, like a README.md and a license file.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Regarding where to place submodules and how to track them:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Submodules are scattered across the repo like that in git. A special file (e.g. &lt;code&gt;.submodules&lt;/code&gt;) that lists the relative directory of each submodule, relative to the .mango folder.&lt;/li&gt;
&lt;li&gt;The submodule directories placed at top level, and keep a *.submodule format.&lt;/li&gt;
&lt;li&gt;The submodule directories placed inside a special &lt;code&gt;.submodules&lt;/code&gt; folder.&lt;/li&gt;
&lt;li&gt;Submodules are not statically documented. Users use paths to invoke them, like using &lt;code&gt;mango path/to/submodule:command&lt;/code&gt;. There is no way short of using brute force to list them though.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Primarily, I chose option 1 for construct, and option 3 for placement and tracking.&lt;/p&gt;
&lt;h2&gt;The Price of a Flat Design&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;A chance of isomorphism should never be missed in architecture design.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I chose these two because they yield a relatively flat file system, without unnecessary time overhead. Thus I reasoned to myself: Mango is designed to be simple, and by far all mango repos adhere to being a flat structure, making it simpler for users to understand, navigate and edit. Unlike git, where outside commands handle the &lt;code&gt;.mango&lt;/code&gt; folder, users should be encouraged, if not required, to directly interact with the mango folder. It is for this reason that I placed great emphasis on keeping directory hierarchies flat and understandable.&lt;/p&gt;
&lt;p&gt;However, just when I was about to finish implementing the submodule system, I realized some issues with this design.&lt;/p&gt;
&lt;p&gt;First and foremost, this design makes it hard to build submodules. When working inside a directory that &lt;em&gt;would be&lt;/em&gt; cloned into as a submodule, the original mango method of searching up the directory tree for &lt;code&gt;.mango&lt;/code&gt; folders would fail to capture the repo, thus disabling users from utilizing &lt;code&gt;mango&lt;/code&gt; to test their work. This can be mitigated by checking not only &lt;code&gt;.mango&lt;/code&gt; directories but also &lt;code&gt;.instructions&lt;/code&gt; files in the mango cli tool, but it seems rather unintuitive and dirty.&lt;/p&gt;
&lt;p&gt;Worse still, there is no reliable and programmatic way to call submodules from submodules, due to the unavailability of the &lt;code&gt;mango&lt;/code&gt; command inside submodule directories. This is a serious limitation, as it prevents users from building more complex submodule systems.&lt;/p&gt;
&lt;p&gt;The problems, in essence, arises from an asymmetry between &lt;code&gt;.mango&lt;/code&gt; folders and submodule ones. The former is recognized by the name, the latter by a position. The lack of isomorphism here created unintended complexities when it comes to development and deployment.&lt;/p&gt;
&lt;p&gt;When designing systems, one should seek consistency and isomorphism wherever possible. This is a lesson learned the hard way. &lt;strong&gt;A chance of isomorphism should never be missed in architecture design.&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;A Better Design&lt;/h2&gt;
&lt;p&gt;After much deliberation, I chose to adopt a better, more consistent design, at the price of more deeply nested directories. We will come to this design choice later.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;~/.mango
├── .instructions
├── .submodules
│   └── builtins
|       ├── .mango
|       |   ├── .templates.registry
|       |   |   └── (template folders)
│       |   ├── .instructions
│       |   ├── .on-add
│       |   ├── .on-add.literal
|       |   ├── .on-install
│       |   └── (builtin mango commands)
|       └── (license and readme files)
├── .templates.registry
|   └── (user defined template folders)
├── .submodules.registry
|   └── (user defined submodules)
└── (user defined mango scripts)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this design, each submodule &lt;strong&gt;is&lt;/strong&gt; a repo, and the &lt;code&gt;.mango&lt;/code&gt; directory resides inside the submodule folder, alongside other files like README.md and LICENSE. This generates a powerful isomorphism that any mango repo is a valid submodule, and any submodule is a valid mango repo. This greatly simplifies development and testing for submodules, and developers can now use &lt;code&gt;mango&lt;/code&gt; commands directly inside submodule directories to access their submodules.&lt;/p&gt;
&lt;p&gt;When submodules are installed, they are git cloned into the special &lt;code&gt;.submodules&lt;/code&gt; folder, and a &lt;code&gt;.on-install&lt;/code&gt; hook is called to perform any additional setup. This design keeps submodules organized and lightweight. Henceforth, submodules are updated using git pull, and removed by simply deleting their folders, no side effects.&lt;/p&gt;
&lt;p&gt;Besides flexibility, another reason I deemed the design a fair tradeoff is that creators should be &lt;strong&gt;discouraged&lt;/strong&gt; from directly editing and referencing submodule files. Come to think of it, submodules are supposed to expose API endpoints for users to call, not files to edit. By nesting them deeper in the directory tree, we can place a deliberate syntax barrier between users and submodule files, encouraging them to use &lt;code&gt;mango&lt;/code&gt; commands as an intermediate layer to access submodules&apos; functionality. This effect, while not intended at first, is indeed beneficial to the overall user experience.&lt;/p&gt;
&lt;h2&gt;What About Templates?&lt;/h2&gt;
&lt;p&gt;So far we have all been talking about submodules, but what about templates?&lt;/p&gt;
&lt;p&gt;The answer is simple: In mango, templates are simply just submodules. They follow the same rule, and the only difference is that, typically, the &lt;code&gt;.on-add&lt;/code&gt; hook is defined to &lt;strong&gt;replace the host repo&apos;s .mango directory with the one inside the template&lt;/strong&gt;. That&apos;s it!&lt;/p&gt;
&lt;p&gt;In order for developers to build submodules and templates more easily, I included two builtin templates: the &lt;em&gt;submodule&lt;/em&gt; template and the &lt;em&gt;template&lt;/em&gt; template. Users can use them with &lt;code&gt;mango @init&lt;/code&gt; to quickly scaffold their own submodule or template repos.&lt;/p&gt;
&lt;p&gt;After they have finished developing their submodules or templates, they can either choose to publish them on git hosting services like github, or store them locally. Two registries are maintained in the host mango repo: &lt;code&gt;.submodules.registry&lt;/code&gt; and &lt;code&gt;.templates.registry&lt;/code&gt;. They act as local git remotes for users, including bare clones of the submodule/template repos, and will be searched when users invoke submodules and templates.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;We&apos;re done! After a month of design and development, mango submodules are finally here. We can now use templates and submodules both online and locally, and reuse code across different mango repos. We have setup a consistent and powerful modularity system that adheres to mango&apos;s core philosophy of simplicity and flexibility.&lt;/p&gt;
&lt;p&gt;Since its first release, mango has come a long way. This submodule system is yet another milestone in mango&apos;s journey towards being a creatively-designed script management tool. I hope you would enjoy using it. Best regards, Norb, head of &lt;a href=&quot;https://github.com/Mango-CLI&quot;&gt;Mango-CLI&lt;/a&gt;.&lt;/p&gt;</content:encoded><h:img src="/_astro/thumbnail.DgA94e1T.png"/><enclosure url="/_astro/thumbnail.DgA94e1T.png"/></item><item><title>Introducing MkData</title><link>https://astro-pure.js.org/blog/introducing-mkdata</link><guid isPermaLink="true">https://astro-pure.js.org/blog/introducing-mkdata</guid><description>Simple but powerful batch data generator based on Python.</description><pubDate>Wed, 08 Oct 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;A Simple Goal&lt;/h2&gt;
&lt;p&gt;It all started a year ago, when, as a freshman majoring computer science, I found myself in constant need of generating large sets of structured data to test algorithms implemented in C++. Most contented themselves with writing small scripts in Python or native C++ to generate random data, but I wanted something more efficient and scalable. I talked with &lt;a href=&quot;https://github.com/RogerFlowey&quot;&gt;RogerFlowey&lt;/a&gt;, and after some heated discussions, MkData was born.&lt;/p&gt;
&lt;p&gt;The idea is simple enough: Programming languages are powerful, yet this power means that for specialized tasks like data generation, boilerplate code is often needed (for instance, to format output). All we need is a flexible &lt;a href=&quot;https://en.wikipedia.org/wiki/Domain-specific_language&quot;&gt;domain-specific language&lt;/a&gt; that can express the structure of the data we want to generate, and a command-line tool (an interpreter) that will generate the data for accordingly.&lt;/p&gt;
&lt;h2&gt;A Journey of Iterations&lt;/h2&gt;
&lt;h3&gt;From GUI to CLI&lt;/h3&gt;
&lt;p&gt;Previously, I had made some attempts at building batch generation tools. The first generation of MkData looks like this:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://astro-pure.js.org/_image?href=%2F_astro%2Fmkdata-old.CfMWHZVC.png&amp;#x26;w=3155&amp;#x26;h=1692&amp;#x26;f=webp&quot; alt=&quot;mkdata-old&quot;&gt;&lt;/p&gt;
&lt;p&gt;I was learning frontend at that time, so I used Vue for the UI. It was a fun project, and (more or less) a good-looking one, but being web app limited its practical functionality. I soon realized that a GUI is not ideal for a generator. It makes much more sense to focus on core language features, and expose a command-line interface for users to interact with.&lt;/p&gt;
&lt;p&gt;I decided to rewrite MkData from scratch, this time as a Python package. After installation, it functions as a command-line tool.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;pip install mkdata
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Or, with other package managers:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;pipx install mkdata
uv tool add mkdata
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Nailing the Syntax&lt;/h3&gt;
&lt;p&gt;Deciding on the syntax of MkData took time. I wanted it to be &lt;strong&gt;as concise as possible&lt;/strong&gt;, without sacrificing extensibility. After several iterations (as a ton of discussions with RogerFlowey), I settled with a half-Pythonic, half-Cpp-ish syntax.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://astro-pure.js.org/_image?href=%2F_astro%2Fmkdata-p0-render.BcjjMhD3.png&amp;#x26;w=1956&amp;#x26;h=995&amp;#x26;f=webp&quot; alt=&quot;MkData Syntax Preview&quot;&gt;&lt;/p&gt;
&lt;p&gt;It might not be perfect, but is as close as we could get to our goal. The beautiful thing is that, since MkData is based on Python, it evaluates all expressions and blocks using Python&apos;s own interpreter. This means that &lt;strong&gt;all Python expressions are valid in MkData&lt;/strong&gt;, making it extremely powerful and extensible. There is even a &lt;code&gt;@python&lt;/code&gt; directive that allows you to write arbitrary Python code blocks in MkData files.&lt;/p&gt;
&lt;p&gt;In accordance to C++ redirection, MkData provides a &lt;code&gt;@redirect&lt;/code&gt; directive to redirect output to files, stdout or stderr. In combination with loops, it can be used to generate multiple files in one go.&lt;/p&gt;
&lt;p&gt;One of the most annoying things about writing data generation scripts is formatting output. The formatting syntax in MkData is done solely through appending format specifiers to the end of each enactive statement, like &lt;code&gt;\n&lt;/code&gt; for newline. This makes it easy to read and write.&lt;/p&gt;
&lt;p&gt;The builtins of MkData (like &lt;code&gt;rint&lt;/code&gt; for random int, &lt;code&gt;rstr&lt;/code&gt; for random string), are, in fact. defined in a python script, which is run at launch-time to capture its environment. If future versions, MkData will support user-defined starting scripts, allowing users to define their own builtins. &lt;a href=&quot;https://github.com/RayZh-hs/mkdata/tree/feature/extend-preimport&quot;&gt;A reform of the standard library&lt;/a&gt; is currently underway at the time of writing, which aims to provide extensive utility as well as a uniform interface for builtins.&lt;/p&gt;
&lt;h3&gt;Speeding Up&lt;/h3&gt;
&lt;p&gt;MkData is implemented in Python, which is not the fastest language out there, but we have done our best to optimize it. Before execution, the script is stepped through and blocks are compiled into &lt;a href=&quot;https://stackoverflow.com/questions/22443939/python-built-in-function-compile-what-is-it-used-for&quot;&gt;Python Code Objects&lt;/a&gt;, and after the tree is fully constructed, it is executed in a single pass. This makes MkData fast enough for most use cases.&lt;/p&gt;
&lt;h2&gt;What&apos;s Next?&lt;/h2&gt;
&lt;p&gt;MkData is still a young project, and there are many features requested so far. Some ideas we have in mind include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Full support for user-defined startup scripts;&lt;/li&gt;
&lt;li&gt;Support for global seeding (implemented in &lt;a href=&quot;https://github.com/RayZh-hs/mkdata/tree/feature/seed&quot;&gt;this branch&lt;/a&gt;);&lt;/li&gt;
&lt;li&gt;Extend the builtin library (see &lt;a href=&quot;https://github.com/RayZh-hs/mkdata/tree/feature/extend-preimport&quot;&gt;this branch&lt;/a&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We have also created a VSCode extension for MkData, providing syntax highlighting and snippets. Feel free to check it out on the &lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=rayzh.mkdata-intellisense&quot;&gt;VSCode Marketplace&lt;/a&gt;.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Here is the source code for all projects mentioned in this post:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/RayZh-hs/mkdata&quot;&gt;MkData&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/RayZh-hs/mkdata-intellisense&quot;&gt;MkData Intellisense&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you have any questions or suggestions, feel free to open an issue on the MkData repository, or reach out to me via &lt;a href=&quot;mailto:ray_zh@sjtu.edu.cn&quot;&gt;email&lt;/a&gt;. Thank you for reading!&lt;/p&gt;
&lt;p&gt;Attribution: Thumbnail image by Eren Namlı on Unsplash&lt;/p&gt;</content:encoded><h:img src="/_astro/thumbnail.BM7yrBd7.jpg"/><enclosure url="/_astro/thumbnail.BM7yrBd7.jpg"/></item><item><title>Introducing Mango</title><link>https://astro-pure.js.org/blog/introducing-mango</link><guid isPermaLink="true">https://astro-pure.js.org/blog/introducing-mango</guid><description>A light-weight script management tool based on the file system.</description><pubDate>Sat, 30 Aug 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;https://github.com/Mango-CLI/Mango&lt;/p&gt;
&lt;p&gt;Script management has always been vital to productivity in software development. Almost every aspiring developer has in his or her toolkit an arsenal of scripts to automate repetitive tasks, streamline workflows, and boost their everyday work efficiency.&lt;/p&gt;
&lt;p&gt;Yet a global &lt;code&gt;/usr/local/bin&lt;/code&gt; directory is not the solution for scope-specific or project-specific scripts. Most builders (pnpm, gradle, uv, etc.) have their own way for allowing users to define and manage scripts within the context of their projects, leading to a kaleidoscope of approaches towards the same problem. Furthermore, global vs. project-specific is about as fine-grained as you can get for customizing user scripts.&lt;/p&gt;
&lt;h2&gt;What Mango is About&lt;/h2&gt;
&lt;p&gt;And yes, here is where mango comes in: To fill in the gap of unified script management, and to provide a file-system based approach to organizing and running scripts.&lt;/p&gt;
&lt;p&gt;Mango allows you to manage your scripts across projects, using folders as scopes to fine-tune your script organization. This offers flexibility beyond traditional hook-based ways adopted by package managers.&lt;/p&gt;
&lt;h2&gt;Designing Mango&lt;/h2&gt;
&lt;p&gt;The core idea of Mango is incredibly simple. Every folder that contains a &lt;code&gt;.mango&lt;/code&gt; folder is a mango repo. Whenever the user invokes:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;mango command-name args
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The mango executable searches up the directory tree for a &lt;code&gt;.mango&lt;/code&gt; folder. If such a folder is found, it maps the command name to a script file registered in that mango repo registry. Appending an &lt;code&gt;@&lt;/code&gt; symbol to the command name enables recursive search (mango will search up dir if no match is found in the first mango repo).&lt;/p&gt;
&lt;p&gt;When the user installs mango, a &lt;code&gt;.mango&lt;/code&gt; folder is created in the user&apos;s home directory, making that directory the user&apos;s &lt;strong&gt;home mango&lt;/strong&gt;. Common utilities will be installed in the home mango, making them globally available via &lt;code&gt;mango @command-name&lt;/code&gt;. So yes: Mango is managed by mango!&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;mango @init --template bash
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will make the current repo a mango repo because &lt;code&gt;init&lt;/code&gt; is a command registered in the home mango, linking to a python script that sets up the folder and initializes the mango environment.&lt;/p&gt;
&lt;p&gt;The same is true for &lt;strong&gt;all mango commands&lt;/strong&gt;. They are nothing &lt;em&gt;magic&lt;/em&gt;, just files in the home mango that you can play around or modify. This makes mango extremely extensible and customizable.&lt;/p&gt;
&lt;h2&gt;Why Mango Matters&lt;/h2&gt;
&lt;p&gt;Mango is yet another script management system. It is nothing fancy, but it does address the need for a unified and extensible scripting solution, in a simple yet elegant way. It is designed to be easy to use, easy to extend, and easy to integrate into existing workflows. This is why personally, I deem Mango a welcoming addition to my workflow, and I have been using it ever since I finished the project.&lt;/p&gt;
&lt;p&gt;If you are interested in the Mango project, feel free to check out the &lt;a href=&quot;https://github.com/Mango-CLI/Mango&quot;&gt;GitHub repository&lt;/a&gt;. We welcome contributions, suggestions, and feedback from the community!&lt;/p&gt;
&lt;p&gt;Happy scripting!&lt;/p&gt;</content:encoded><h:img src="/_astro/thumbnail.Ba09MPNR.jpg"/><enclosure url="/_astro/thumbnail.Ba09MPNR.jpg"/></item></channel></rss>