<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0">
<channel>
<title>Coder Legion - Recent posts tagged native</title>
<link>https://coderlegion.com/tag/native</link>
<description>Powered by Question2Answer</description>
<item>
<title>Why GitWand is Rust, not Electron: what native performance actually buys a Git client</title>
<link>https://coderlegion.com/25097/why-gitwand-is-rust-not-electron-what-native-performance-actually-buys-a-git-client</link>
<description>&lt;p&gt;It's been a while since the last post here (v3.5, July 10). Since then, three releases have shipped: v3.6.0 (a handful of workflow polish items), v3.6.6 (a pure dev-loop and CI performance pass, no product surface), and v3.7.0 (Commit Review, a local AI pass over your staged changes). A straight changelog recap would cover all three, but it would miss the thing that actually connects them.&lt;/p&gt;
&lt;p&gt;Every one of those releases is a direct consequence of a decision made on day one: build on Tauri 2 and Rust instead of Electron, and keep the actual conflict-resolution logic in a deliberately portable, zero-dependency TypeScript package instead of folding it into the Rust backend. That split sounds like an implementation detail. It isn't. It's the reason a 5-repo Launchpad refresh takes 30ms instead of most of a second, the reason a 30-second timeout bug fixed a few days ago (#166) had a one-line fix instead of a rewrite, and the reason the new Commit Review feature never has to touch a GitWand server. This post is about that decision, with real numbers pulled straight from the codebase instead of the usual &quot;native is faster, trust us.&quot;&lt;/p&gt;
&lt;h3 id=&quot;the-bet-and-who-else-made-it&quot;&gt;The bet, and who else made it&lt;/h3&gt;
&lt;p&gt;GitWand ships as roughly an 8 MB installed binary. GitKraken, built on Electron, ships in the ~150 MB class: a full bundled Chromium plus a full bundled Node.js runtime, running alongside each other, for an app that mostly renders text and spawns &lt;code&gt;git&lt;/code&gt;. GitHub Desktop is the same story. The gap shows up at startup (GitWand is sub-1 second) and it shows up on large repos, where an Electron app's single JS heap has to hold and garbage-collect everything the UI touches.&lt;/p&gt;
&lt;p&gt;To be fair to the field: GitWand isn't the only one making this bet anymore. GitButler is Tauri + Rust too. GitComet skips the webview entirely and goes pure Rust with GPUI. Strand is Tauri + React. Being native, in 2026, is closer to table stakes for a new Git client than a differentiator; RelaGit is the interesting counter-example, choosing Electron even with a SolidJS frontend for its fine-grained reactivity. The real question isn't &quot;who avoided Electron,&quot; it's what each of these tools actually does with the native layer once it has it. That's the part worth walking through.&lt;/p&gt;
&lt;h3 id=&quot;what-rust-buys-fearless-concurrency-with-a-number-attached&quot;&gt;What Rust buys: fearless concurrency, with a number attached&lt;/h3&gt;
&lt;p&gt;Rust's ownership model turns a whole class of concurrency bugs into compile errors instead of production incidents. That's a nice sentence to put in a pitch deck. Here's what it looks like in a file that ships in the app today.&lt;/p&gt;
&lt;p&gt;GitWand's multi-repo dashboard (Launchpad) needs the status of every repo in your workspace: branch, ahead/behind, modified-file count. The naive version spawns four &lt;code&gt;git&lt;/code&gt; subprocesses per repo, one after another. GitWand's Rust backend does two things instead: each repo's status comes from a single in-process &lt;code&gt;libgit2&lt;/code&gt; call rather than four subprocess spawns, and every repo in the workspace gets processed in parallel via &lt;code&gt;rayon&lt;/code&gt;'s &lt;code&gt;into_par_iter()&lt;/code&gt;, one core per repo instead of one core doing all of them in sequence. The comment sitting next to that code in the source states the measured result plainly: a 5-repo workspace listing went from about 750ms wall-clock to about 30ms in the typical case. That's not a marketing number, it's a comment next to a &lt;code&gt;#[tauri::command]&lt;/code&gt; that ships today.&lt;/p&gt;
&lt;p&gt;The same pattern shows up all over the backend, because once the tool exists, using it costs nothing extra: PR &lt;code&gt;+/-&lt;/code&gt; stat enrichment across GitHub, GitLab, Azure DevOps, and Bitbucket all fan out per-PR diff computation across cores instead of looping; submodule status checks across a repo's submodules run in parallel; per-branch top-author lookups for the branch picker do too. A few days ago, a regression brought back a 30-second &lt;code&gt;gh_list_prs&lt;/code&gt; timeout: the per-PR stats loop had gone back to running one &lt;code&gt;git diff --numstat&lt;/code&gt; at a time. The fix wasn't a rewrite or a new thread pool, it was swapping a &lt;code&gt;for&lt;/code&gt; loop for &lt;code&gt;.par_iter_mut()&lt;/code&gt;. None of these needed hand-rolled synchronization or a bespoke worker pool. The parallel version and the serial version are the same number of lines, and if two of those parallel closures ever raced on the same mutable data, that's a compile error, not a bug report from a user with a corrupted status badge.&lt;/p&gt;
&lt;h3 id=&quot;what-rust-doesn-t-need-to-buy-the-conflict-engine-stays-typescript-on-purpose&quot;&gt;What Rust doesn't need to buy: the conflict engine stays TypeScript, on purpose&lt;/h3&gt;
&lt;p&gt;Here's the part a &quot;Rust is fast&quot; pitch usually skips: the actual pattern-classification engine, the code that decides &lt;code&gt;same_change&lt;/code&gt; versus &lt;code&gt;one_side_change&lt;/code&gt; versus &lt;code&gt;complex&lt;/code&gt; and merges JSON, YAML, and lockfiles key by key, is not written in Rust. It lives in &lt;code&gt;@gitwand/core&lt;/code&gt;, and that package is deliberately zero-Node, browser-safe TypeScript.&lt;/p&gt;
&lt;p&gt;That's not a compromise, it's a second, equally deliberate architectural line. Classifying a few hundred lines of diff text against nine pattern rules finishes in single-digit milliseconds no matter what language it's written in; Rust's raw throughput wouldn't move that number in any way a user could feel. What Rust &lt;em&gt;would&lt;/em&gt; have cost is portability: because the engine has no Node dependency, the exact same code runs inside the desktop app, in the CLI (&lt;code&gt;npx @gitwand/cli resolve&lt;/code&gt;), inside the MCP server that AI agents call, and could run directly in a browser tomorrow with no changes. The rule GitWand actually follows isn't &quot;everything is Rust.&quot; It's narrower and, we think, more useful: Rust owns the boundary with the operating system (spawning &lt;code&gt;git&lt;/code&gt;, walking the filesystem, talking to forge APIs, the whole app shell), and the deterministic algorithmic core stays a small, dependency-light, portable package that isn't tied to any one runtime.&lt;/p&gt;
&lt;h3 id=&quot;the-unglamorous-release-v3-6-6&quot;&gt;The unglamorous release: v3.6.6&lt;/h3&gt;
&lt;p&gt;v3.6.6 shipped no new product surface at all, just a dev-loop and CI performance pass, and it's the release that best shows the bet compounding on itself. Because the entire backend is one Rust crate, the same profiling discipline used to make the app fast also applies to making the &lt;em&gt;build&lt;/em&gt; fast: a &lt;code&gt;[profile.dev]&lt;/code&gt; tuned for lighter debug info cut a post-edit &lt;code&gt;cargo build&lt;/code&gt; from about 21 seconds to about 6.5. On the CI side, a &lt;code&gt;desktop&lt;/code&gt; job that produced three fully-signed release bundles on every single push to &lt;code&gt;main&lt;/code&gt;, bundles nobody downloaded, was replaced with a fast &lt;code&gt;rust-check&lt;/code&gt; job (fmt, clippy, check, test) that finally runs the app's 217 Rust unit tests in CI for the first time, saving roughly 230 billed CI minutes per push. On the TypeScript side, Vitest's global &lt;code&gt;jsdom&lt;/code&gt; environment (needed by maybe a fifth of the test files, paid by all of them) was scoped down per-file, cutting environment setup time from about 96 seconds to about 17 across the suite.&lt;/p&gt;
&lt;p&gt;Worth mentioning: before touching any of it, every claim in the plan for this work got re-measured against the actual codebase, not assumed. Several turned out to be wrong. &quot;Any edit recompiles and relinks everything&quot; wasn't true, &lt;code&gt;cargo check&lt;/code&gt; after a real edit came back in under 2 seconds; the real cost was in the codegen-and-link step of a full &lt;code&gt;cargo build&lt;/code&gt;. &quot;The old &lt;code&gt;jsdom&lt;/code&gt; setup costs 100 to 300ms per file&quot; was an underestimate by roughly 10x once actually profiled. That's the same discipline the conflict engine's confidence scores are built on: don't ship a number you haven't checked.&lt;/p&gt;
&lt;h3 id=&quot;commit-review-and-why-local-first-is-the-real-differentiator&quot;&gt;Commit Review, and why local-first is the real differentiator&lt;/h3&gt;
&lt;p&gt;v3.7.0's headline feature, Commit Review, runs an AI pass over your staged changes right in the Changes panel before you commit, with inline findings and a &quot;Fix with agent&quot; action that hands them to a terminal AI session (Claude Code, opencode, or Codex) already running against your repo. What matters about it architecturally is what it &lt;em&gt;doesn't&lt;/em&gt; do: it never calls a GitWand-run server. The review runs against whichever AI CLI you already have installed, on your machine, over your own already-open agent session.&lt;/p&gt;
&lt;p&gt;That's the same &quot;zero mandatory cloud&quot; value the conflict engine already embodies, applied to review instead of merge. It's also the sharper contrast with where a chunk of the market is headed: tools positioning code-intelligence features as a metered cloud API (Greptile's own &quot;Genius API&quot; is priced at $0.45 per request) are betting that developers will pay per call for something GitWand ships as a local, free, opt-in feature built on tools you already run. Being local-first for conflict resolution and local-first for review isn't two separate decisions, it's the same one, applied twice.&lt;/p&gt;
&lt;h3 id=&quot;the-small-stuff-v3-6-0&quot;&gt;The small stuff: v3.6.0&lt;/h3&gt;
&lt;p&gt;Between the two, v3.6.0 shipped things that don't need an architecture section to justify: a one-click &quot;Update branch&quot; prompt when you check out something behind its upstream, and a non-blocking handoff when an interactive rebase hits a conflict (issue #128), so the conflict editor no longer traps you behind a modal. These are the kind of small interactions that only feel good because there's no Electron process and no garbage-collector pause standing between the click and the result. The architecture doesn't just enable the big numbers, it's also why the boring stuff feels instant.&lt;/p&gt;
&lt;h3 id=&quot;where-the-bet-goes-next&quot;&gt;Where the bet goes next&lt;/h3&gt;
&lt;p&gt;The roadmap's next stop, v3.9.0 (Live Repo), applies the same philosophy one layer up: a Rust &lt;code&gt;notify&lt;/code&gt; crate watcher replaces the current 2-second status poll with real filesystem events, more read paths move to in-process &lt;code&gt;libgit2&lt;/code&gt;, and separately, the portable TypeScript core's diff/parse hot path gets moved off the main thread into a Web Worker. Same rule, two languages: Rust handles OS-level events natively and cheaply, and the portable core gets pushed off the render thread the way any JavaScript does it. One architecture, one non-negotiable: the UI thread never waits on either of them.&lt;/p&gt;
&lt;h3 id=&quot;the-market-read&quot;&gt;The market read&lt;/h3&gt;
&lt;p&gt;The Git GUI space is splitting into two camps: Electron incumbents charging a subscription for cloud AI features (GitKraken at $8/mo, with its advanced and AI features gated behind an account), and a newer wave of native, mostly free, often open-source tools built on Rust or a comparable native stack (GitButler, GitComet, Strand, and GitWand, with RelaGit staying on Electron by choice). Being native is fast becoming the price of entry for that second group, not what sets any one of them apart. What actually differentiates GitWand inside it is what the native layer gets used for: a conflict-resolution engine that classifies instead of guesses, multi-repo workflows that get genuinely (and measurably) faster because of how the backend is built, and an AI layer that never assumes your code should leave your machine.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Download GitWand for macOS, Linux, or Windows from &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/devlint/GitWand/releases&quot;&gt;GitHub Releases&lt;/a&gt;, read the &lt;a rel=&quot;nofollow&quot; href=&quot;/changelog&quot;&gt;full changelog&lt;/a&gt;, or see how the numbers stack up against specific tools on the &lt;a rel=&quot;nofollow&quot; href=&quot;/compare/&quot;&gt;compare pages&lt;/a&gt;.&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/25097/why-gitwand-is-rust-not-electron-what-native-performance-actually-buys-a-git-client</guid>
<pubDate>Fri, 21 Aug 2026 15:52:00 +0000</pubDate>
</item>
<item>
<title>Create a Video Chat App in React Native with Pre-built API</title>
<link>https://coderlegion.com/2889/create-a-video-chat-app-in-react-native-with-pre-built-api</link>
<description>&lt;p&gt;Want to create a video chat app like Zoom, Google Meet or MS Teams for your business? In this tutorial, we'll walk through how to build a 1:1 video calling app.&lt;/p&gt;
&lt;p&gt;We will start with creating a video call feature where one user can initiate a video call and the other can receive, accept or reject it.&lt;/p&gt;
&lt;p&gt;The app will be built in React Native and we'll use a &lt;a rel=&quot;nofollow&quot; href=&quot;https://www.mirrorfly.com/react-native-chat-sdk.php&quot;&gt;pre-built video call solution from MirrorFly&lt;/a&gt;.&lt;br&gt;
If you already have an app, you can use the below steps to add the video chat feature. If not, you can use this sample app, upon which you'll add the video calling features as instructed below. &lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Since we'll build the app in React Native, we'll need the below pre-requisites:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Node.js: &amp;gt;= 18.20.4 &lt;/li&gt;
&lt;li&gt;npm: &amp;gt;= 10.7.0&lt;/li&gt;
&lt;li&gt;React Native: &amp;gt;= 0.73.0 and &amp;lt;=0.75.4&lt;/li&gt;
&lt;li&gt;SDK License Key Firebase Cloud Messaging (FCM) setup for Android&lt;/li&gt;
&lt;li&gt;VOIP push notification support for iOS&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; This post assumes you have the basic understanding on handling React Native.&lt;/p&gt;
&lt;h3 id=&quot;step-1-install-the-sdk&quot;&gt;Step 1: Install the SDK&lt;/h3&gt;
&lt;p&gt;Install the SDK from npm:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;npm install mirrorfly-reactnative-sdk
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The SDK will have all the methods to initialize the call, register the user, connect and make calls.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import { SDK } from 'mirrorfly-reactnative-sdk';
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After installation, this line imports the SDK to get the methods initializeSDK, register, connect, getJid, into your project&lt;/p&gt;
&lt;h3 id=&quot;step-2-adding-peer-dependencies&quot;&gt;Step 2: Adding Peer Dependencies&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;{
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;  &quot;react-native-webrtc&quot;: &quot;124.0.4&quot;,&lt;br&gt;
  &quot;react-native-background-timer&quot;: &quot;^2.4.1&quot;,&lt;br&gt;
  &quot;react-native-permissions&quot;: &quot;^5.2.1&quot;&lt;br&gt;
}&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;To support the SDK to run without any errors, you'll need the following npm packages:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;react-native-webrtc:&lt;/strong&gt; This package provides the JavaScript access to&lt;br&gt;
native WebRTC APIs for enabling real-time audio and video streams on&lt;br&gt;
your app. It exports objects like RTCPeerConnection, MediaStream,&lt;br&gt;
MediaDevices, etc.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;react-native-background-timer:&lt;/strong&gt; This keeps your app awake when calls&lt;br&gt;
are ongoing. This package is the one that provides Methods like&lt;br&gt;
setInterval, setTimeout, clearInterval, etc., that continue to work&lt;br&gt;
even when the app is minimized.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;react-native-permissions:&lt;/strong&gt; This package is responsible for initiating&lt;br&gt;
requests for mic, camera, and notification permissions from the OS.&lt;br&gt;
It checks and asks for runtime permissions with methods like&lt;br&gt;
check(), request(), and openSettings().&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;step-3-initializing-the-sdk&quot;&gt;Step 3: Initializing the SDK&lt;/h3&gt;
&lt;p&gt;When you initialize the SDK, you need it to listen to the connection status. For this you'll need to define a callback as mentioned below. &lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const connectionListener = (response) =&amp;gt; {
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;  if (response.status === &quot;CONNECTED&quot;) {&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;console.log(&quot;Connected to MirrorFly&quot;);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;  } else if (response.status === &quot;DISCONNECTED&quot;) {&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;console.log(&quot;Disconnected from MirrorFly&quot;);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;  }&lt;br&gt;
};&lt;/p&gt;
&lt;p&gt;This line logs a message when the client connects or disconnects from the server.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const initializeObj = {
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;  apiBaseUrl: &quot;&lt;a rel=&quot;nofollow&quot; href=&quot;https://api-preprod-sandbox.mirrorfly.com/api/v1&quot;&gt;https://api-preprod-sandbox.mirrorfly.com/api/v1&lt;/a&gt;&quot;,&lt;br&gt;
  licenseKey: &quot;YOUR_LICENSE_KEY_HERE&quot;,&lt;br&gt;
  isTrialLicenseKey: true,&lt;br&gt;
  callbackListeners: {&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;connectionListener,
// Add more listeners if needed (e.g., incomingCallListener)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;  },&lt;br&gt;
};&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;apiBaseUrl:&lt;/strong&gt; URL of the backend you are connecting to.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;licenseKey:&lt;/strong&gt; Your SDK key for authentication.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;isTrialLicenseKey:&lt;/strong&gt; Boolean to indicate trial mode.&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;callbackListeners:&lt;/strong&gt; List of event listeners your app reacts to.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;await SDK.initializeSDK(initializeObj);&lt;/p&gt;
&lt;p&gt;Now, this line initializes the SDK with your configuration and sets up event listeners. Most importantly, this must be called before you use other functions in the SDK like register() or connect().&lt;/p&gt;
&lt;h3 id=&quot;step-4-registering-a-new-user&quot;&gt;Step 4: Registering a New User&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;You'll need to import modules for:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;FCM (Android push token) &lt;/li&gt;
&lt;li&gt;VOIP push notifications (iOS)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For this, use this line:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import messaging from '@react-native-firebase/messaging';
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;import RNVoipPushNotification from 'react-native-voip-push-notification';&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Here,&lt;/strong&gt; &lt;br&gt;
addEventListener('register', callback): Listens for the VOIP token from iOS.&lt;br&gt;
messaging().getToken(): Gets the FCM token from Firebase for Android.&lt;br&gt;
SDK.register(...): Registers a new user using:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;user123:&lt;/strong&gt; Unique user ID&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;fcmToken:&lt;/strong&gt; Required for push calls on Android&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;voipToken:&lt;/strong&gt; Required for VOIP on iOS&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;DEV&lt;/strong&gt; ? false : true: Sets IS_PRODUCTION based on dev or release mode&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;RNVoipPushNotification.addEventListener('register', async (voipToken) =&amp;gt; {
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;  const fcmToken = await messaging().getToken();&lt;br&gt;
  await SDK.register('user123', fcmToken, voipToken, &lt;strong&gt;DEV&lt;/strong&gt; ? false : true);&lt;br&gt;
});&lt;/p&gt;
&lt;p&gt;Next, to receive VoIP push notification on iOS, you need to trigger the registration process by adding this line:&lt;/p&gt;
&lt;p&gt;RNVoipPushNotification.registerVoipToken();&lt;/p&gt;
&lt;h3 id=&quot;step-5-connecting-the-user&quot;&gt;Step 5: Connecting the User&lt;/h3&gt;
&lt;p&gt;Using the credentials obtained from the register() step, this line logs the registered user into the server.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;await SDK.connect(&quot;user123&quot;, &quot;securePassword123&quot;);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Once connected, the user will be able to start or receive calls. The connection listeners will start monitoring the connection status. &lt;/p&gt;
&lt;h3 id=&quot;step-6-getting-user-jid&quot;&gt;Step 6: Getting User JID&lt;/h3&gt;
&lt;p&gt;Next, add this line:&lt;/p&gt;
&lt;p&gt;const userJid = SDK.getJid(&quot;user123&quot;);&lt;/p&gt;
&lt;p&gt;This will return the Jabber ID (JID) of a user. JID is an identification system used internally by the XMPP system to uniquely identify users. You can therefore use userJid when initiating or accepting calls.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;With these steps, you’ve built the core structure of a one-on-one &lt;a rel=&quot;nofollow&quot; href=&quot;https://www.contus.com/blog/best-react-native-chat-apis-sdk/&quot;&gt;video calling app&lt;/a&gt;. You now have&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Real-time communication between users&lt;/li&gt;
&lt;li&gt;Customizable call UI&lt;/li&gt;
&lt;li&gt;Call control features (answer, decline, hang up)&lt;/li&gt;
&lt;li&gt;SDK-level connection and call event tracking&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;From here, you can implement beyond the basics like outgoing and incoming call UI, Audio controls (mute/unmute), and analytics. &lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Got queries?&lt;/strong&gt; Feel free to add your questions in the comments. I'd be more than happy to join a healthy discussion on the technologies.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Learn more in this video tutorial&lt;/strong&gt;, &lt;a rel=&quot;nofollow&quot; href=&quot;https://www.youtube.com/watch?v=TL7RTm6g0Ek&quot;&gt;How to build a video chat app with React Native?&lt;/a&gt;&lt;/p&gt;
</description>
<category>Getting Started</category>
<guid isPermaLink="true">https://coderlegion.com/2889/create-a-video-chat-app-in-react-native-with-pre-built-api</guid>
<pubDate>Tue, 06 May 2025 06:08:30 +0000</pubDate>
</item>
<item>
<title>Debugging Shaders on macOS: Instruments vs. Gpumkat</title>
<link>https://coderlegion.com/1702/debugging-shaders-on-macos-instruments-vs-gpumkat</link>
<description>&lt;h2 id=&quot;debugging-shaders-on-macos-instruments-vs-gpumkat&quot;&gt;Debugging Shaders on macOS: Instruments vs. Gpumkat&lt;/h2&gt;
&lt;p&gt;Debugging and optimizing Metal shaders on macOS has long been reliant on Apple's Instruments tool. However, a new alternative, &lt;strong&gt;gpumkat&lt;/strong&gt;, has emerged, offering a different approach with enhanced debugging features. In this article, we will compare Instruments and gpumkat, highlighting their differences, strengths, and why gpumkat may be the superior choice for many developers.&lt;/p&gt;
&lt;h3 id=&quot;instruments-the-traditional-tool&quot;&gt;Instruments: The Traditional Tool&lt;/h3&gt;
&lt;h4 id=&quot;features-&quot;&gt;Features:&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Provides detailed profiling of GPU activity&lt;/li&gt;
&lt;li&gt;Tracks memory usage and performance metrics&lt;/li&gt;
&lt;li&gt;Offers GPU counters for in-depth analysis&lt;/li&gt;
&lt;li&gt;Integrated with Xcode&lt;/li&gt;
&lt;li&gt;Best suited for hardware-specific insights&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;limitations-&quot;&gt;Limitations:&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;No built-in shader debugging tools&lt;/li&gt;
&lt;li&gt;Lacks robust breakpoint and step-through debugging for Metal shaders&lt;/li&gt;
&lt;li&gt;Requires deep knowledge of GPU internals to interpret data&lt;/li&gt;
&lt;li&gt;Limited support for timeline-based debugging and trace analysis&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;introducing-gpumkat&quot;&gt;Introducing Gpumkat&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Gpumkat&lt;/strong&gt; is a GPU kernel analysis tool designed for Metal API debugging and performance analysis. Unlike Instruments, which is focused on hardware profiling, gpumkat offers a broader range of tools specifically for shader debugging and optimization.&lt;/p&gt;
&lt;h4 id=&quot;key-features-&quot;&gt;Key Features:&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Performance Analysis&lt;/strong&gt;: Tracks execution time, cache hit rates, and memory usage.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Shader Debugging&lt;/strong&gt;: Step-by-step debugging, variable printing, and breakpoints.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Energy Consumption Insights&lt;/strong&gt;: Estimates GPU power draw and energy efficiency.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Interface Metrics&lt;/strong&gt;: Monitors how buffers and pipelines interact.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;GPU Software States&lt;/strong&gt;: Tracks command execution flow.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Stack Tracing &amp;amp; Tracing Timelines&lt;/strong&gt;: Logs and visualizes execution sequences.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Error Handling&lt;/strong&gt;: Captures warnings, memory errors, and validation issues.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Low-End GPU Simulation&lt;/strong&gt;: Tests shader performance under constrained hardware conditions.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;why-gpumkat-is-the-better-alternative&quot;&gt;Why Gpumkat is the Better Alternative&lt;/h3&gt;
&lt;h4 id=&quot;1-superior-debugging-tools&quot;&gt;1. &lt;strong&gt;Superior Debugging Tools&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;While Instruments provides GPU counters and profiling, it lacks a dedicated shader debugger. Gpumkat allows developers to set breakpoints, inspect variables, and step through shader execution, making it far more effective for diagnosing shader issues.&lt;/p&gt;
&lt;h4 id=&quot;2-comprehensive-performance-analysis&quot;&gt;2. &lt;strong&gt;Comprehensive Performance Analysis&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;Gpumkat offers in-depth insights into cache hit rates, memory bandwidth, and processing unit availability—data that is difficult to extract from Instruments alone.&lt;/p&gt;
&lt;h4 id=&quot;3-better-error-handling&quot;&gt;3. &lt;strong&gt;Better Error Handling&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;With built-in error detection for memory leaks, shader validation failures, and runtime warnings, gpumkat prevents common pitfalls that are harder to catch using Instruments.&lt;/p&gt;
&lt;h4 id=&quot;4-simulated-low-end-gpu-testing&quot;&gt;4. &lt;strong&gt;Simulated Low-End GPU Testing&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;Gpumkat allows developers to simulate lower-end GPUs to test how shaders perform under constrained conditions. This feature is crucial for ensuring compatibility with a range of hardware, something Instruments does not provide.&lt;/p&gt;
&lt;h4 id=&quot;5-enhanced-trace-logging-and-timeline-recording&quot;&gt;5. &lt;strong&gt;Enhanced Trace Logging and Timeline Recording&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;While Instruments provides time-based tracking, gpumkat offers a more detailed execution timeline, helping developers pinpoint slowdowns and inefficiencies in their shaders.&lt;/p&gt;
&lt;h3 id=&quot;when-to-use-instruments-vs-gpumkat&quot;&gt;When to Use Instruments vs. Gpumkat&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;Use Case               &lt;/th&gt;&lt;th&gt;Instruments &lt;/th&gt;&lt;th&gt;Gpumkat&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Hardware-Specific Profiling &lt;/td&gt;&lt;td&gt;✅ &lt;/td&gt;&lt;td&gt;❌&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Shader Debugging &lt;/td&gt;&lt;td&gt;❌ &lt;/td&gt;&lt;td&gt;✅&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Breakpoints &amp;amp; Step Debugging &lt;/td&gt;&lt;td&gt;❌ &lt;/td&gt;&lt;td&gt;✅&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Memory &amp;amp; Cache Analysis &lt;/td&gt;&lt;td&gt;✅ &lt;/td&gt;&lt;td&gt;✅&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Error Detection &lt;/td&gt;&lt;td&gt;❌ &lt;/td&gt;&lt;td&gt;✅&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Low-End GPU Simulation &lt;/td&gt;&lt;td&gt;❌ &lt;/td&gt;&lt;td&gt;✅&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Timeline &amp;amp; Trace Recording &lt;/td&gt;&lt;td&gt;✅ (basic) &lt;/td&gt;&lt;td&gt;✅ (detailed)&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&quot;installing-gpumkat&quot;&gt;Installing Gpumkat&lt;/h3&gt;
&lt;p&gt;Gpumkat is easy to install and requires minimal dependencies:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;curl -L -o gpumkat.tar.gz https://github.com/MetalLikeCuda/gpumkat/releases/download/%s/gpumkat.tar.gz \
    &amp;amp;&amp;amp; tar -xvzf gpumkat.tar.gz \
    &amp;amp;&amp;amp; cd gpumkat \
    &amp;amp;&amp;amp; sudo sh install.sh
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Replace &lt;code&gt;%s&lt;/code&gt; with the latest version number.&lt;/p&gt;
&lt;h3 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;For developers focused on deep GPU performance profiling, &lt;strong&gt;Instruments&lt;/strong&gt; remains the go-to tool. However, if you need &lt;strong&gt;shader debugging, error handling, and simulated performance testing&lt;/strong&gt;, &lt;strong&gt;gpumkat&lt;/strong&gt; is the clear winner. Its comprehensive feature set makes it an invaluable tool for Metal developers looking to optimize their shaders efficiently.&lt;/p&gt;
&lt;h4 id=&quot;you-can-see-the-repository-here&quot;&gt;You can see the repository here&lt;/h4&gt;
&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/MetalLikeCuda/gpumkat&quot;&gt;https://github.com/MetalLikeCuda/gpumkat&lt;/a&gt;&lt;/p&gt;
</description>
<category>Open Source Tools</category>
<guid isPermaLink="true">https://coderlegion.com/1702/debugging-shaders-on-macos-instruments-vs-gpumkat</guid>
<pubDate>Sat, 29 Mar 2025 20:34:03 +0000</pubDate>
</item>
</channel>
</rss>