Category Archives: Tech

Apple Vision Pro Demo Impressions

I tried out the Apple Vision Pro (AVP) hardware in an Apple store today. The ball was in Apple’s court. I really wanted to be impressed by the hardware and put me over the edge to pick one up and develop apps for it. I’ve released Day 1 apps for the Apple Watch & ARKit (iOS 11), and I believe in the future of AR for productivity.

Not Sharp

Unfortunately, when I wore the AVP, the content (text, images, etc.) was not razor sharp. I could use the device and navigate the OS without an issue, but I was expecting next-gen sharpness on the AVP displays.

My guess is I could try different distances (closer or further) from the screen to find the distance where all the content is sharp and crisp. Probably try different light seals. I couldn’t achieve the level of sharpness that I expect from any 2020 device (phone, HD monitor, etc).

Also, there was an opening at the bottom of my headset (towards my nose). I thought the light seals were supposed to block 360 degrees of light around the headset and not leave a small gap. That gap was normal per the Apple rep.


Apple did a great job with the demo. The demo was seated (smart) and focused on VR content, not passthrough use cases.

The OS (visionOS) was simple to use. Pinching to drag around or press buttons worked fine with hand gestures. When I tried to resize windows (bottom corners) or use two hands to pull apart, I ran into problems with certain apps where it wouldn’t work.

Content (2D vs 3D)

My imagined ideal use case would be having several large macOS screens in front of me to get work done. However, Apple marketing seems to be focused on entertainment (big TV in front of you) as their selling point.

The problem (in my opinion) is that the content was not great. Spatial content, shot on what I presumed are iPhone 15 Pro Maxes or AVPs, seemed low resolution to me. Enlarging an iPhone photo to fill up your entire room’s wall doesn’t work that well. It lacked detail. Even viewing a Panorama (shot on iPhone? not sure), the resolution was not great when viewed at such a large size.

Part of the demos included immersive environments. The environments were impressive since they were built natively for the device and 3D rendered. Viewing a photo from the moon environment was great since the nearby 3D rocks on the ground really sell the illusion.

I personally felt the other content fell apart. Spatial videos (shot with iPhone 15 PM?) were fun but it didn’t feel immersive to me since moving around lacked the convincing parallax experience you get from viewing things in your every day life.

While internet AVP users seem to enjoy viewing 2D movies on a giant, virtual screen, I think there is a huge opportunity for companies to build 3D immersive environments or games for users to be in (and interact with). Using the AVP’s state of the art hardware to view 2D images is like watching television without sound – a missed opportunity.


Despite the hardware issues (I suspect the light seal), I’d be interested in making AR apps for the AVP. Paying almost $4K to buy a dev kit and develop for Apple is a tough sell for an indie developer. I honestly think Apple should have a program for developers to borrow AVPs and build apps.

Installing Ruby 2.X on Intel macOS Monterey (12.6)

In this guide, we’ll be using rvm & homebrew to install Ruby 2.X on our Intel Mac. The key is to specify the location of openssl.

First, make sure you have Xcode Command Line Tools installed on your mac. You can install it with

        xcode-select --install

Then install openssl (v1.1):

        brew install openssl@1.1

To install Ruby on my Mac, I’ve had to specify the openssl directory when compiling Ruby. Make sure to replace “2.7.8” with your target Ruby version.

        rvm install 2.7.8 --with-openssl-dir=`brew --prefix openssl@1.1`

You can set this version of Ruby as your default version with rvm:

        rvm use --default 2.7.8

That’s it! Installing older versions of Ruby isn’t too tough.

Installing Windows 11 on a new PC built from scratch

I recently built a PC from parts I got at my local MicroCenter and online. Building the PC was tough, but there were no surprises.

Installing Windows 11 Pro was really, really difficult. I’m shocked since installing software (especially a prominent offering of Microsoft) is supposed to be trivial and work everywhere.

With my PC parts put together, I was able to see the BIOS screen on my monitor. I made sure CSM (Compatibility Support Module) was off and UEFI (Unified Extensible Firmware Interface) was enabled.

I restarted my computer and plugged in my Windows 11 installation USB drive. (Sidenote: I recommend creating the installation USB from Microsoft’s Media Creation Tool on a Windows PC. I tried to create a USB install stick from macOS and it did not work.)

Going through the menu options, I was getting cryptic errors: “Windows could not prepare the computer to boot into the next phase of installation. To install windows, restart the installation“. The error message was unhelpful so I spent time googling for answers and restarting my computer countless times.

From what I can tell, my copy of Windows 11 Pro cannot install from a USB drive. This is surprising since using a USB drive is the de facto installation method in 2023. Almost nobody has a CD/DVD drive to install Windows like we used to 10 years ago.

I had to use command line tools in the Windows installation process to create a local SSD partition, copy Windows 11 from my USB to the new partition, and install Windows from the SSD. This was extremely not user friendly and took me well over 3 hours of trial and error to eventually come up with a solution to install Windows. What gives Microsoft? Is installing Windows from a USB drive seamlessly not a priority?

Here are the commands I ran to install Windows 11. My notes (after the # below) are my best guesses as to what is happening. Note: this will format/wipe/erase your drive. PROCEED AT YOUR OWN RISK.

You can get to the command line interface from the disk selection screen. Press Shift + F10 to open and enter.

# enter diskpart tool

# view your disks
list disk 

# selects the 1st disk (make sure you select your primary SSD)
select disk 0 

# wipe the selected disk

# set the selected disk to GPT format. this is important!
convert gpt 

create partition primary size=52000 
# the size (52000) varies. Just make sure it fits Windows 11 and is within the size of your SSD

# format the selected disk to NTFS
format fs=ntfs 

# assign a drive letter to the selected disk

# view your list of volumes
list volume 
# make a note of the letters for your new SSD partition & USB stick

# exit diskpart

# change to your flash drive. Use the correct letter (may or may not be E:)
cd E:

# copy from USB to your new SSD partition
# Use the correct letters (e: & c:) below
xcopy e: c:/s /e /h /c


After following the steps above, you have now created a partition on your SSD with a copy of the install USB contents. It is important to EXIT the Windows installer. Do NOT continue with the Windows menus.

Restart your computer. When your computer is off (during the restart), make sure to remove the USB stick. You want your computer to boot from your new partition and not the USB stick.

If everything goes well, you should be able to install Windows 11 successfully.

During the Windows setup, I had to run a command (OOBE\BYPASSNRO) to install Windows without connecting to the internet. This was a chicken and egg problem since I didn’t have any WiFi firmware setup on my computer, so I couldn’t easily get any firmware updates. Also Windows wasn’t even setup yet, so I couldn’t use Windows to install the WiFi firmware either.

As a final step, I wanted to remove the disk partition created during the Windows install process (above). It’s all been a blur given how hard it was to install Windows 11 in the first place. Thankfully, after Windows 11 was already installed on my computer, I was able to re-run the Windows 11 setup process, remove the partition, and install Windows without an issue.

How I cleaned up 3M spam comments in a WordPress blog

Tl;dr: delete them.

Last week, I received an alert, my blog’s database was too large (> 3GB) and had to be upgraded to a premium plan. Paying a new monthly fee for something I don’t need made no sense, so I looked into the database.

Most of the space was used by two WP tables: wp_comments & wp_commentmeta. Their sizes being roughly 2.2 GB & 1.8 GB respectively.

Upon logging into the WP admin panel, I could see a long neglected blog. There were 3.1M comments, and somehow 2.7M were approved.

3M comments (the vast majority are assumed to be spam)

My first approach was to use akismet (Automattic’s spam filtering service) to process the comments. I went into my MySQL database and marked the comments from late 2019 (arbitrary cutoff date) from approved (comment_approved=1) to pending (comment_approved=0).

WordPress’s comments section has a handy button to Check For Spam with Akismet. I tried this, but it was taking too long. I honestly think it would take a month to check my ~3M comments. Since the browser would time out, this process had to be manually monitored (not practical).

While your comments section may have lots of legitimate comments, my understanding of my comments is that they are 99.999% spam for the past few years. This is because my blog has been largely ignored and is no longer current. In fact, searching for my blog doesn’t even show up on Google. The lack of HTTPS (now fixed) and endless spam comments probably pushed the SEO so low that *only* spammers know about the site to post comments.

With the assumption of nearly 3M comments as spam, here’s how I cleaned it up:

  1. As mentioned above, I moved all the comments from late 2019 to pending (comment_approved=0). I tried using phpMyAdmin but had to eventually use a GUI (TablePlus on Mac) to run SQL.
    UPDATE wp_comments set comment_approved = '0' WHERE comment_date > '2019-10-01' AND comment_approved = '1';
  2. Delete all my pending comments:
    DELETE FROM wp_comments WHERE comment_approved = '0';
  3. Clean up my meta comments table (wp_commentmeta):
    DELETE FROM wp_commentmeta WHERE comment_id NOT IN ( SELECT comment_id FROM wp_comments );
  4. Clean up table overhead. Overhead was making my tables still take up GBs of space even though the vast majority of comments were deleted.
    OPTIMIZE TABLE wp_comments;
    OPTIMIZE TABLE wp_commentmeta;

Using a desktop GUI to run MySQL was fast and efficient. Before and after I executed my SQL clean up commands, I checked the row counts so I could have some confidence in the executed commands.

I still have ~10K comments left on my site. Some are legitimate, some are spam. I’m letting Akismet take a pass through these 10K comments, and then I’ll clean up the rest manually.

Setting up your Mac to create a Playdate app

This guide is written on macOS Monterey (v12.3).

playdate simulator

Here are instructions on setting up & running the most barebones app possible on macOS. There are probably better ways to do this, but here’s one way that works for me.

  1. Download & install the SDK via

  2. Update your ~/.zshrc file with the following line:

    export PLAYDATE_SDK_PATH=/Users/rex/Developer/PlaydateSDK

    Obviously you want to replace “rex” with your username.

  3. Create a new folder for your project (anywhere)
    mkdir playdate_hello_world
    cd playdate_hello_world

  4. Create a VS Code folder & settings file
    mkdir .vscode
    touch .vscode/settings.json

  5. Put the following into your new settings.json file. Make sure to replace the 2 instances of “rex” with your username

    "Lua.runtime.version": "Lua 5.4",
    "Lua.diagnostics.disable": [
    "Lua.diagnostics.globals": [
    "Lua.runtime.nonstandardSymbol": [
    "Lua.workspace.library": [
    "Lua.workspace.preloadFileSize": 1000,
    "playdate.sdkPath": "/Users/rex/Developer/PlaydateSDK"

    (Apologies for the formatting. WordPress & code doesn’t mix well). You can copy & paste above (and make sure to replace the 2 “rex”s)

  6. Create a simple file for your app
    mkdir source
    touch source/main.lua

    Copy the following into main.lua:

    import "CoreLibs/object"
    import "CoreLibs/graphics"
    import "CoreLibs/sprites"
    import "CoreLibs/timer"

    function playdate.update()
    print "Hello world"

    Obviously this code does not do very much. It’s super, super basic, but it compiles & runs!

  7. Install the following VS Code extensions (sumneko.lua, jep-a.lua-plus, and Orta.playdate)

  8. Run your app on the Playdate Simulator with VS Code.

    Press Cmd + Shift + P and select & run [Run app in Playdate simulator]

  9. That’s it! Your app is now running on the Playdate sim. You can view print statements by using Window > Console.

For more comprehensive details, refer to the SDK documentation:

For the sample files discussed here, see repo:

New app alert (Copy Cleaner for macOS)

I’ve just released my first macOS app, a menu bar app. It’s called Copy Cleaner and it works in the background to remove tracking from URLs that are copied to your clipboard. The UX is very seamless since you use your mac normally, and common trackers (utm_source, etc) are removed automatically for you.

Working on a macOS app (on the mac App Store) was a nice diversion for me. I’m used to working in Xcode, but not on mac apps. Granted a menu bar app is different from a traditional desktop application that sits in your dock.

I built this app since it’s tackles something that I run into weekly. When I’m browsing iOS, JS, ruby, etc. newsletters, I end up clicking on many long URLs – filled with query trackers. By building this app, I don’t have to clean up my URLs manually any more. This app takes care of it.


Copy this:

You’ll paste this:

That’s it. The app works silently in the background. With Apple’s Clipboard and the app running on your mac, the URL cleaning works on both mac & iPhone.

Let me know if you have any questions. You can reach me on Twitter @rexfeng

P.S. – We’re on Product Hunt!

Using the MIYA Pro Mac Keyboard

I recently picked up the Ducky MIYA Pro Mac White LED 65% Dye Sub PBT Mechanical Keyboard. This seems to be a rebranded Varmilo keyboard as the cables are branded with Varmilo.

The form factor (tenkeyless) is nice and compact. The lack of numpad on the right gives me much more space for my mouse. As expected from a mechanical keyboard, the sound of the keys is noticeable.

I went with Cherry MX Brown switches. The keyboard typing feel is nice but requires more effort than a flat chiclet keyboard.

I went with this keyboard since I wanted different things: 1.) mac support, 2.) tenkeyless, and 3.) cherry mx browns.

The keyboard comes with an instruction manual in Chinese & English. I find the documentation to be lacking. You’d think a keyboard would be plug and play, but this keyboard is more complicated due to the top row sharing Number keys & Mac media/shortcut keys.

When I got my keyboard, it took me some time to figure out that Fn + A turns the keyboard into Mac mode. Fn + W would change it back to the default, Windows mode. I also had to activate “default mode” (it’s unclear to me what this means) by pressing Fn + D to be able to use the Number keys as numbers and have my Mac recognize the keyboard configuration.

Other things that confused me for a bit was the PgUp & PgDn alternating lights. Apparently one or the other never turns off? This is annoying for someone who values the little details and prefers certain aesthetics. I’ve read online that it lights up (one or the other) to indicate whether the keyboard’s top row is in Numbers mode or Media mode. To switch between the two, it’s Fn + PgUp for Numbers and Fn + PgDn for Media.

To use F1-F12, it’s Fn+PgDn, then Fn+F1 for F1 (and so on through F12).

As a software engineer, it took some time to figure out that Fn + Esc activates the backtick key (`).

Overall, the small form factor & hearty typing key feel are great. It’s unfortunate that a keyboard has a learning curve, but that’s the price to pay for a condensed layout where keys have double or triple duty.

iOS Developer iPhone (Dec 2018)

As an indie iOS app developer, keeping up with Apple’s hardware can get expensive fast. From the Mac to the iPhones and iPads.

I’m focusing on native iPhone apps and currently use an iPhone 7 as my daily driver. I’m considering getting a new iPhone and want to find the right balance between 1.) phone size I want to use daily and 2.) phone is optimal for App Store Connect previews (videos) & screenshots.

Since I’m an AR app developer, having iPhone hardware is essential (the Simulator doesn’t cut it).

Looking at the state of iPhone hardware today (Dec 2018), some quick Googling shows that the iPhone 7, 7+/8+, and X form factors are the most common in the US.

When we look at Apple’s App preview & screenshot guidelines, it tells us that the 5.5 inch (iPhone 8+, etc) form factor is required (screenshots) and recommended (app previews).

For 2019, my guess is that supporting the 5.5 inch (8+) form factor and the 5.8 inch (X/XS) on App Store Connect would give me the most bang for my buck. It would be nice to have both a XS & XS Max to test with, but that’s way out of my budget.

Curiously enough, the app preview video resolutions are the same across the X line (X, XS, XS Max, XR at 886 x 1920 pixels (when portrait). The video resolution is bigger at 1080 x 1920 pixels for the plus line (8+, etc).

Using App Store Connect, I was able to manually verify the different screenshot upload resolutions for the iPhone XS Max (1242 × 2688), iPhone XS (1125 × 2436), and iPhone 8+ (1242 × 2208). It seems like there is no point to try to take or upload iPhone XR screenshots.

In summary, the iPhone plus (8+, etc) line is the most important for app previews & screenshots. After that, the XS & XS Max (in that order) will give you more App Store Connect coverage with diminishing returns.

DJI Spark – First Impressions

I’m new to drones and picked up a DJI Spark Fly More Combo during Prime Day, where it was $50 off. The price before tax was $500. The combo includes the remote control, an extra battery, and more helpful accessories.

The Spark hardware is a marvel of engineering. It’s not that big, but it packs a lot of technology inside. I chose the Spark since I wanted something small & novice friendly. The operating noise is very loud for my taste, but it’s to be expected for current drones.

The setup experience to start using the drone was very confusing. After charging my batteries & the remote control, it took me a long time to understand how to pair & fly the Spark.

The key revelation is that the Spark drone and the remote control each have their own WiFi network. Depending on which way you want to fly (using phone or remote), you have to connect to the right WiFi network. The problem is that the WiFi network(s) don’t always show up.

I couldn’t find any Spark WiFi networks, so I had to hold the power button on my drone for 10 seconds to reset the drone’s WiFi. Then I could connect to the drone with my phone.

Despite being able to connect to my phone, I wanted to use my remote (instead of the phone’s virtual joysticks). This link about rebooting the remote helped fix my issue. With the remote WiFi to phone being so unreliable, I’ve gone and ordered a 3rd party Lightning to USB Cable.

The drone to phone or remote pairing process is very painful. The process involves pressing & holding various buttons on the drone or remote and waiting several seconds for different beeps & lights. It’s about as user unfriendly as you could get. There is potential for a firmware update or DJI GO 4 mobile app update that would help resolve some of these pain points, but I wouldn’t hold my breath.

Once you are able to pair the drone to the remote control (and pair your phone to the remote control), the flying part is fun. There’s a learning curve, but the remote control’s hardware joysticks make flying intuitive.

One other note, I’m currently residing in Los Angeles. LA is not drone friendly as there are many airports and restrictions. It’s very likely you can’t fly where you want to in LA. Definitely check out where you can fly drones in your area before purchasing a drone.

My Aging MacBook Situation

My personal daily driver is a 2011 MacBook Air (MBA). I’ve shipped 6 iPhone apps from it. For a computer bought in 2011, I’m happy with how long it has lasted.

I am interested in buying a new MacBook Pro (MBP) to replace my aging MacBook Air, but I’m not sure what to do. The possible choices I see are:

1.) the current MBP (June 2017 version)
2.) wait ? months for an updated MBP (most likely a minor CPU refresh)
3.) a 2015 MBP version (older hardware style with IMHO better keyboard)

Reasons to upgrade sooner:
* Xcode runs poorly on my MBA. Storyboard, Simulator, and Playgrounds are barely usable.
* macOS Mojave will not run on my MacBook Air. It’s only a matter of time before I’m locked out of macOS & Xcode updates.
* Apple announced a Keyboard Service Program.
* As a professional software developer, I can easily justify 2-3 year upgrade cycles.
* My MBA is showing it’s age; the battery is virtually gone.

Reasons to upgrade later:
* My MBA is able to run Xcode 9 (current) and will hopefully run Xcode 10 GM.
* Buying after a new hardware refresh (minor CPU bump most likely) maximizes the currentness of the purchase. This may not be rational, but it’s a factor nonetheless.
* My iPhone app development is primarily dependent on iPhone hardware updates & Xcode, not my Mac.
* Indecision – since none of the current MBP options (2015 or 2017) are very appealing, I can wait it out.

Reasons that don’t make a difference:
* I don’t like typing on the current generation MBP keyboard, but the next significant MBP hardware refresh is probably a few years away (too long).
* USB-C – I’ve found a Multi-Port Adapter (dongle) that works for me.


In retrospect, I should have bought a decently equipped 2015 MBP in 2015.

If Xcode 10 GM doesn’t work on my Mac, then I’ll be forced to buy a new Mac right away. Otherwise I will wait around hoping Apple decides to update the MBP.