Yahallo! I'm sero.
I main dabble in front-end web development, and aspire to expand my skillset to the back end. I daily drive a Lenovo laptop that runs on Ubuntu, and I have recently turned my old 2014 Macbook Air into an MX Linux setup.
This blog-esque markdown details some of the miscellaneous dev I have done in my free time. This will serve as my blog until I eventually set up a proper site when I get time off. Do stay tuned. In the meantime, Check out my Github profile here. You can also find me on Discord: @manystarsapart
Thanks for being here and hope you have as much fun reading these entries as I did writing them!
Signing off, sero (22 Sep 2025)
- 22/03/2025: Fish shell init script
- 27/04/2025: VTuber avatar on Ubuntu
- 14/06/2025: Attempt on automating a Caffeine workflow
- 17/08/2025: Fish Shell Prompt
- 17/08/2025: Arknights on Waydroid
- 03/09/2025: Revitalising my old Macbook with Linux
- 20/09/2025: Expanding & Customising IBus Rime
- 24/09/2025: iPhone Terminal
My fish config file. a simple piece of initialiser code to make the terminal more convenient for dev purposes.
Written for fish shell.
Authored 22/03/2025.
Each time the terminal is launched, or when user runs fp, the terminal outputs a randomised personalised greeting message (in Chinese) from a curated list, with two parts:
- Flavour text
- Greeting message
See examples here.
The command fg can also be run to manually call a randomised greeting. Additionally, use fg -la to list all available greetings in the greeting pool.
Edit 17/08/2025: there are now time-specific greetings. Likewise, you may check the greeting pool for the current time of the day using fg -la.
(Updated 22/09/2025)
c-->clearl-->ls -lhalr-->ls -lhaR(recursively lists all files in the dir)s-->sudofp-->fish --private(launches fish in private mode)copy-->| xclip -selection clipboard(pipes output of command into clipboard)commands-->cat ~/Documents/scripts/commands_help.txt | less(shows a guide to these abbreviated commands)
power-saver-->powerprofilesctl set power-saverbalanced-->powerprofilesctl set balancedperformance-->powerprofilesctl set performancecpufreq-->watch -n 0.5 "grep 'cpu MHz' /proc/cpuinfo | head -n $(nproc)"(shows frequencies of all CPU cores)sysinfo-->sudo -E ~/Documents/scripts/printsysinfo_new.sh | xclip -selection clipboard(copies debug information to clipboard)printsysinfo-->sudo -E ~/Documents/scripts/printsysinfo_new.sh(prints debug information in terminal)
sau-->sudo apt updatesai-->sudo apt installsaa-->sudo apt autoremove
gad-->git add .gc-->git commit -S -m "%"where % becomes cursor locationgp-->git pushgpl-->git pullnrd-->npm run dev(vite)nrb-->npm run build(vite)nrp-->npm run preview(vite)
-
co-->codium(launches codium) -
ghidra-->~/ghidra_11.3.2_PUBLIC/ghidraRun(launches ghidra) -
autopsy-->~/autopsy/autopsy-4.22.1/bin/autopsy(launches autopsy) -
openseeface-->~/Documents/runOpenSeeFace.sh(for virtual avatar)
-
This script also sets the Node.js version to the latest version as my machine defaults to using Node 12. This is probably due to a mismatch in $PATH, but the temporary fix using
nvm use latestworks, so I am sticking with that. -
This init script works in tandem with the Fish prompt I wrote. Do check that one out as well if you are interested.
(Updated 17/08/2025)
This aims to serve as a guide and document my endeavor in figuring out how to render my virtual avatar model on Ubuntu.
Authored 27/04/2025.
- According to some users online, Lutris sometimes works better than Bottles. I use Bottles simply because I already have Bottles installed.
- This set of instructions was immensely helpful. Thank you u/TheRogueGrunt's Reddit post.
- Run Bottles
- Run VSeeFace through Bottles and select a model
- Set up the green screen
- Run OBS Studio
- Select VSeeFace as Pipwire window capture input
- Open Terminal
- Start tracking face by running the script through typing
openseeface(fish abbr) or directly running~/Documents/runOpenSeeFace.sh
- Turn on Virtual Camera in OBS if using avatar as facecam (Discord, Meet, Teams etc)
- Turn on Stream and configure streaming if streaming to websites
- Default:
Alt + 1 - Closer:
Alt + 2 - Close-up:
Alt + 3 - Extreme Close-up:
Alt + 4 - Full body:
Alt + 5
... and now you are adequately set up to start streaming using your model.
- OS: Ubuntu 22.04.5 LTS x86_64
- Kernel: 6.8.0-58-generic
- Shell: fish 4.0.2
- DE: GNOME 42.9
- WM: Mutter
- Terminal: gnome-terminal
- CPU: Intel Ultra 7 155H (22) @ 4.500GHz
- GPU: Intel Device 7d55
- Memory: 8712MiB / 15594MiB
All versions below are the versions of software used at the time of writing.
- Bottles 51.21: https://flathub.org/apps/com.usebottles.bottles
- VSeeFace 1.13.38c2: https://www.vseeface.icu/#download
- OBS Studio 30.2.3: https://obsproject.com/download
- Fish shell 4.0.2: https://fishshell.com/
- Set up Bottles
- Create an application named
VSeeFaceand click into it - In the top right dropdown, select
Browse Files...to open the C drive folder - Extract everything from the VSeeFace ZIP archive into
Program Filesof the C drive - Under
Programs, clickAdd Shortcutsand findVSeeFace.exefrom the extracted folder - Under
Options, clickSettings - Change runner to
sys-wine-10.0, ensure DXVK isdxvk-2.6.1and VKD3D isvkd3d-proton-2.14.1 - Under
Displaynavigate into theAdvanced Display SettingsMenu, and turn onVirtual Desktop,Fullscreen Mouse Capture, andTake Focus - Return to
Programsand run the executable to boot up VSeeFace
- Move the
.vrmmodel file (or files of other compatible formats) into the Documents folder in the C drive (NOTE: not your Ubuntu Documents folder!) - In VSeeFace, add your avatar from that folder into the local avatar list
sudo apt-get install python3 python3-pip python3-virtualenv git- Clone the OpenSeeFace repository by emilianavt:
git clone https://github.com/emilianavt/OpenSeeFace cd ~/OpenSeeFacevirtualenv -p python3 envbash(because I am in fish terminal)source env/bin/activatepip3 install onnxruntime==1.21.1 opencv-python pillow numpy
bashcd ~/OpenSeeFacesource env/bin/activatepython facetracker.py -c 0 --discard-after 0 --scan-every 2 --no-3d-adapt 1 --max-feature-updates 900 --model 3 --faces 1
The above command produces the smoothest tracking motion for my machine. For higher-end machines one could probably experiment with more graphics-heavy configurations. See OpenSeeFace README.
- Navigate back to
VSeeFace > Cameraand select[OpenSeeFace Tracking]. You may leaveMicrophone,Listen IPandPortas their default values - Select your avatar and load it by clicking
Start
- Download any green screen wallpaper online
- Add the green screen into the bottle's files.
Documentsfolder works fine - In VSeeFace, click
Props > Addthen select the green screen to add it - Under
Settingsfor Props, drag the slider to get maximumDistance to avatar, maximumSmoothing, and uncheckAlways on top - Using an unused camera (inside
Settings > General Settings > Camera), alt-click to have your avatar back-face you. Then alt-scroll to zoom out until your avatar is very small - Drag the green screen prop ONTO the back of your tiny avatar. While dragging, scroll to increase the size of the green screen to cover the entirety of your background if possible
- Change the camera perspective back to the main one you are using via
Settings > General Settings > Camera. Green screen should show behind the avatar
- Boot up OBS Studio
- Create a new scene
- Create a new source:
Screen Capture (PipeWire) - Select the VSeeFace application window. Now your avatar should show up
- Right click the source, select
Transform > Edit Transform... - Under
Crop, crop out the Wine Desktop borders such that only VSeeFace's application background is shown. CloseEdit Transform - Right click the source, select
Filters, and add aChroma Keyfilter. SelectGreenforKey Colour Type. CloseFilters - (Optional) Add an image source as background behind your avatar
Linux's virtual camera is trippy. v4l2loopback-dkms in Ubuntu 22.04 repositories (0.12.7) does not build on Linux kernel 6.8 due to a change in the kernel’s string handling functions. Specifically, strlcpy was removed from the kernel, but v4l2loopback 0.12.7 still tries to use it, causing the build to fail with the error: implicit declaration of function ‘strlcpy’; did you mean ‘strscpy’?
To resolve this issue, build the latest version of v4l2loopback-dkms that has a patch for this.
sudo apt remove v4l2loopback-dkms
git clone https://github.com/umlaeute/v4l2loopback.git
cd v4l2loopback
make
sudo make install
sudo modprobe v4l2loopback devices=1 exclusive_caps=1 card_label="OBS-VirtualCam"TL;DR: My version of GNOME does not support it & I don't want to upgrade to Ubuntu 24.04 yet.
Authored 14/06/2025.
While using my laptop to study, I often leave the laptop on a single screen for a long time as I solve the problems on paper. However, the laptop wants to turn on screensaver and go to sleep. I chanced upon Caffeine, a GNOME extension by eonpatapon, which solved my problem by providing me with a button to toggle between keeping the screen on persistently and going to sleep after a while. (I want that for all of my devices now...)
On some days, I keep forgetting to turn on caffeine when coming back to a suspended session (before you tell me, yes, I do know there is an option to persist across sessions but I do not want that behaviour). Hence, naturally as any lazy person would do, I set out to write a script to help with that.
- The script would activate every time I start a desktop session.
- The script would ask me if I wished to turn on Caffeine.
- If yes, turn on Caffeine.
- If no, Caffeine remains off.
Simple. Easily done with a few lines of bash script, right?
Since I already have a fish init script set up, I can simply run the script when that init script runs. No issue.
I explored zenity and its functionalities, and first tried using notification:
zenity --notification --text "Caffeine?"But with zenity notifications there exist no way (as of now) to respond to that notification being clicked. Moreover, I am perpetually on Do Not Disturb mode, meaning I cannot see the notification on starting a session anyway.
(You may be thinking "What about notify-send?" Well, it could not respond to the notification being clicked either. DND problem is still there as well)
Let's try something else. Zenity has an info dialogue that I can use to run my Caffeine script after clicking "Ok":
if zenity --info --text "Caffeine?"; then
# run caffeine
fiBut I wanted a way to opt out. No go.
Then I tried question:
if zenity --question --text "Caffeine?"; then
# yes
echo "Yes"
else
# no
echo "No"
fiWow! This is exactly what I had wanted. We are basically set.
Now that we have that handy script to prompt us each time, let's figure out how to turn on caffeine in the command line!
After having read through the Github README, I deduced Caffeine does not seem to support control through commands. I did not want to toggle the entire GNOME extension on and off either, as I still wanted the ability to turn on Caffeine later on in the session.
I explored Caffeine's settings again, and found that it has a hotkey option. We might be able to emulate a keypress in the script to activate Caffeine!
So I set the hotkey to super + c:
Great! One step closer.
Now let's find a way to emulate super + c.
I know of xdotool, and wanted to use that to emulate my keypresses with something like this:
xdotool key super+cHowever, xdotool works for X11, not Wayland (which I am comfortable with using, since Wayland is the default display server for my machine). I went on to look for alternatives for Wayland, and found wtype, ydotool, and diowtype.
First let's try wtype. This was my idea:
- Press and hold
super - Press
c - Release
super
wtype -M win -k c -m winThis returns:
Compositor does not support the virtual keyboard protocol
Oh boy. After digging and being led to the Mutter (GNOME's core window manager and compositor) forum, apparently GNOME does not support the virtual-keyboard-unstable-v1 Wayland protocol needed for these to work due to security reasons. This means wtype and ydotool will not work on my machine.
This forum also mentions libei, which sounds potentially promising. Let's set that aside for later use.
The thing about diowtype is despite the fact that it can indeed run on my machine, it only emulates one single keypress at a time, not combinations. Caffeine's settings do not accept single-keypress hotkeys, so I cannot use this either.
Then I looked into libei:
In fact, Mutter had actually integrated libei in the newer versions!
I was heartened until I realised Mutter only supports libei from Ubuntu 24.04 onwards, while I used my trusty 22.02 Jammy.
Darn... I was not ready to upgrade my system so I had to call it a day.
To end this mildly disappointing section off on a slightly more lighthearted note, here is a section from the creator's blog regarding libei:
What does all this have to do with eggs? "Ei", "Eis", "Brei", and "Reis" are, respectively, the German words for "egg", "ice" or "ice cream", "mush" (think: porridge) and "rice". There you go, now you can go on holidays to a German speaking country and sustain yourself on a nutritionally imbalanced diet.
In the end, I settled with everything I had up to Part II. There would be a prompt at startup asking if I wanted to activate Caffeine, and if I selected Yes, it would prompt me to use my hotkey (super + c) to activate it. This would serve more as a reminder rather than an automation process, but I will settle for this.
Final files can be found here.
This was an interesting dive into an aspect that I have hardly come into contact with. It took two hours on a splendid Saturday morning that I could have spent studying.
Upgrading to Ubuntu 24.04 and trying to fix broken dependencies last year has left a fowl taste in my mouth. Maybe in the near future, when I can wield Linux better, I will do so and finally get my daily morning fix of virtual Caffeine.
Putting this script inside the fish startup prompt, I realised, was not convenient at all. I had two problems:
-
The script did not run on resuming a suspended session; and
-
The script always ran whenever I started my terminal.
Hence, I decided to look into startup prompts in order to truly give myself the experience I wanted. This time, I tried using an autostart desktop file for running the script on startup, as well as a user service to detect when the user logs back into a suspended session.
I created a file in ~/.config/autostart named caffeineReminder.desktop.
I opted for autostart over putting the script inside /etc/init.d/ or update-rc.d because this is, after all, a GUI prompt. I did not want to run it as root user as well.
This part was slightly trickier. First, I made a caffeine-on-resume.service file and put it inside ~/.config/systemd/user.
Then, the service needs to be enabled:
systemctl --user enable caffeine-on-resume.serviceThis created the correct symlink and added my service as a dependency to a non-existent unit suspend.target.
HOWEVER. I realised this is not how it works. Apparently, this runs the script when I suspend the session itself (I believe this was the case?), not when I resume. Thus I removed it.
systemctl --user stop caffeine-on-resume.service
systemctl --user disable caffeine-on-resume.serviceLet's try this again. Digging again, I found a wonderful guide by Ubuntuhandbook on this subject. Unfortunately, this seems to be running the script as root and I am unsure how to make the prompt work on this one.
Maybe next time. For now, at least the startup script works.
I have also enabled Caffeine in my newly installed MX Linux system on my Macbook Air. I did not set up a customised script for it as there is no need for it, so Caffeine remains as it is, out of the box, on that machine.
An attempt on further customising my terminal. Written for Fish, inspired by the inbuilt Informative style, but with some extra features.
Authored 17/08/2025.
Format: [Timestamp] ($USER) ($hostname) (directory path)
- Changes colour if user is root.
Shows time taken for a command to execute if more than 3s was used.
Relays relevant information in the context line & changes the prompt symbols based on identified directories.
-
Git: Shows branch & current status.
-
Node: Shows node version.
-
Python Venv: Shows virtual environment name.
-
Docker: Shows docker context.
(Note that Git takes precedence over Venv for prompt symbols.)
Shows background jobs (if any) taking place in the session.
Alerts if disk space used exceeds 90%.
(No demo. My disk space has yet to exceed 90%.)
Alerts if user is in a directory that is read-only.
As depth of directories increases, colour of directory increasingly becomes more red. Additionally, directory name is shortened to its first letter for directories >5 depth up from the working directory.
This was a fun journey as I gradually learnt more about my machine. There are many more fun things that I can do, and I am thrilled to explore them when I have time.
I consulted Claude for some of the more technical aspects of status detection, which helped me immensely in overcoming these hurdles.
That is all. Thank you for reading till the end of this project. See you in the next one soon.
Authored 17/08/2025.
I came across a Waydroid demonstration video on Bilibili. It piqued enough of my curiosity to get me tinkering, so here is my journey.
I should probably have searched up a guide and saved some effort during the first few reinstallations though.
- I installed Waydroid from the official website.
- I initialised Waydroid using Vanilla at first, but realised that in order to get Arknights from Google Play Store, I needed a Google Play Store.
- This meant I needed an emulator that has Google Apps. and Vanilla did not cut it. Great.
- Let's Reinstall.
- Google Apps acquired! Now we boot into Waydroid!
- Waydroid's documentation states we need to get this emulated device certified by Google before we can do anything. This took around 20 minutes on Google's side.
- Now let's head to the Play Store and download Ark... Oh. "Your device isn't compatible with this version."
- I found an essential script to install, but I tinkered around and Waydroid eventually stopped booting. Congratulations. </3.
- Let's Reinstall.
- Now that I have installed again from the official source, I made sure to also clone the Waydroid Script directory and install libhoudini through the CLI installation.
- The reason why libhoudini is needed is that Arknights is compiled to run on the
ARMarchitecture. This means I cannot directly run Arknights on myx86laptop. There needs to be an ARM translation library in place, and what works best for Intel is apparently libhoudini. - Finally! After having downloaded libhoudini (and removing the nodataperm hack which caused black screens), I could download Arknights.
- Installation done. I clicked the icon on the desktop. I boot to a black screen. Darn. Linux is full of surprises.
- Let's Reinstall.
-
Let's keep trying. This should be the right way to go, but I have not yet figured out what is stumping me. Some reference for future me:
-
https://www.reddit.com/r/waydroid/comments/x988mk/installing_both_libhoudini_and_libdnk/
-
https://blog.etineres.fr/posts/how-to-play-arknights-on-fedora-41-with-waydroid/
-
worst case: apk
There has to be some way with which I can install and run Arknights smoothly on Waydroid. I will try some other methods in time to come. This war is not over until it is over.
Presently it is getting late. I will call it a night for now, and hope the debugging solution comes to me in a dream.
- It has been a few days. I decided to try the
Vanillaversion of Waydroid & go the APK route. Let's see. - The apk I used to install the app is 100mb in size while the xapk on the same website is 1gb. I tried the xapk using
sudo app install Downloads/(xapk file)but the app did not install at all. Guess xapk does not work. - Next, using the apk itself, the app installed. Woo! Let's open it.
TBC
Authored 03/09/2025.
I have an old Macbook Air. I cannot remember when I had acquired it, but it runs on OS X 10.9.5 (13F1911). This machine is an 11-inch, early 2014 model and I have been using it for over ten years. It has even been bootcamped and also dualboots a Windows 7 system. Talk about retro.
Unfortunately, the battery has been degraded through the years of usage, meaning the machine can only be booted up if it is connected to the AC power source (at just the right angle, by the way – if the wire were to be twisted in any other way, the machine just stops). Furthermore, the native OS X is very outdated and supports virtually no modern app. The Windows 7 system can still run a bunch of things surprisingly well, but its limit is Minecraft 1.16, as it struggles to render anything but distorted polygons on 1.17 when I tested it with my buddies.
Enough said. Let's try to revitalise this good old friend of mine.
Originally, I had wanted to use Arch Linux and subsequently get the I-use-Arch-btw pass. However, I thought twice:
The concern mostly lies in the rolling release aspect. I would love to not have to fix everything everywhere all at once, so maybe Arch next time.
From browsing online forums, I learnt of MX Linux (I'm always locked out of their website for some reason though). Its Debian base coupled with its popularity among the old-computer-linux community appealed greatly to me and I was sold instantly.
I checked to see if my old Macbook could run MX Linux, and chanced upon Action Retro's video, in which he installed MX Linux on a Macbook Air that is as old as my own. If he could do it, I can do it.
I downloaded MX Linux's .iso file for Live USB (Version MX 23.6 "Libretto") from Sourceforge, then etched it to one of my few remaining USB sticks using balenaEtcher since I had no access to Rufus on my Ubuntu system. Initially, I was worried about whether my 4GB USB stick could be used, but the .iso file turned out to only be 2GB. Talk about lightweight distros.
Do note that apparently you need to install firmware updates and set the volume on your OS X to an acceptable volume (or mute) first before wiping it out entirely. Installing firmware updates was not really an option for me as there were few updates compatible with my computer remaining on the App Store. The volume carries through to determine the volume setting for the booting chime of your new system, so I adjusted it to around 50%.
The Live USB successfully booted, and took a surprisingly short time to boot up MX Linux from the USB for my ancient machine.
However, life is full of surprises; this time it is not a pleasant one. The MX Linux system apparently cannot detect my SSD at all, as observed from the Regular install using the entire disk option being greyed out in the Partition page.
Using sudo fdisk -l only shows sda1 and sda2, and both of them are the boot USB itself. I even booted to Ubuntu 24's live USB to check if it was the MX Linux system's issue. No luck either.
This seemed really concerning from a quick search online, as one of the antiX forum users seemed to need to factory reset the entire computer and mess with BIOS settings and also remove Windows in order to fix it. I knew how to do none of these procedures.
Thankfully, after further digging, I chanced upon an AskUbuntu forum post that deals with a Macbook Air instead. The previous forum post had been about a Lenovo Ideapad which had a different problem. For my issue, I simply had to add intel_iommu=off in the live CD kernel options, which was a much simpler procedure.
I followed the instructions and added the aforementioned option. For those interested, here's the procedure:
-
Boot to the GRUB screen and press arrow keys to highlight the GRUB entry to edit.
-
Press
e, which should bring you to the kernel options (some systems may require pressing tab / space before that first?ejust works for me though). -
Using arrow keys to navigate, move the cursor down to the
linuxrow. Addintel_iommu=offat the back. -
Press
ctrl+xORF10to boot using these options.
The machine booted up, and with bated breath I started the MX Linux installation process. The procedure had worked! I used 28GB (25%) for Root and the remaining 85GB (75%) for Home. There was more room than I had envisioned as I was used to having only effectively 30GB per system on that machine due to the dualboot settings.
Old is not always gold. Once I got past the previous screens, I was hit with yet another error, this time quite concerning:
The disks with the partitions you selected for installation pass the
SMART monitor test (smartctl), but the tests indicate it will have a
higher than average failure rate in the near future.If unsure,
please exit the Installer and run GSmartControl for more
information.
Do you want to continue?
Opening GSmartControl to check, it seems like my SSD has gone through its fair share of wear and tear (my Power_On_Hours is 6958... that averages to around 2 hours of screen time every single day for ten years! Gee...). I aborted the operation because the warning sounded quite frightening – Reallocated Sector Count was 1, meaning one bad sector has been found and remapped. The overall health seemed fine from the report though, so I proceeded to install MX Linux again after some consideration.
"Osmanthus wine tastes the same as I remember."
Let's install MX Linux for real!
By mine I mean my own. Not mine BitCoin.
Now that MX Linux has been properly installed, I decided to follow the footsteps of (probably) every Linux user. Here are some things that I did to customise this machine, partly referencing FOSSLinux:
- Increase font size (to 11) (
settings > appearance) - Set theme (
settings > appearance) - Wallpaper & splash screen (
settings > desktop) - Install Caffeine
- Add items to panel in items menu & Customise the panel to look like the Ubuntu one I'm used to
- Fix potential screen tearing (
mx tools > tweak > compositor > vblank: xpresent) - Enable double click (
mx tools > tweak > config options > disable single click for both desktop & thunar) - Customise the desktop clock widget (
mx tools > conky) - Make booting to mxlinux 3s (
mx tools > boot options) - Enable antiX adblock
- Enable default firewall options
- Install Fish shell & use my fish config script (greatly cut down)
- Install Spotify
Voila!
Art source seems to be 阳_伞 according to a video, but I cannot tell for sure.
Added 07/09/2025.
Today I entered a video call and realised the webcam could not be detected. Worry not, though, for I found the exact post (or rather string of posts) to solve my issue. It led me to a script on Github that seems to work, so I tried it.
Here's what I did:
nano installwebcam.sh
# (pastes the script in)
sudo chmod +x ./installwebcam.sh
sudo ./installwebcam.shUnfortunately, I ran into some issues when I ran this script. An error popped up, saying:
install: cannot change permissions of ‘//usr/lib/firmware/facetimehd’: No such file or directory
Sounds like an easy fix. I just made the directory and ran the script again:
sudo mkdir -p /usr/lib/firmware/facetimehd
sudo ./installwebcam.shOkay. This time it worked, albeit with some errors still:
Warning: modules_install: missing 'System.map' file. Skipping depmod.
modprobe: FATAL: Module bdc_pci not found.
These should be harmless as I do not have bdc_pci in my system anyway. For the depmod, I ran it manually:
sudo depmod -aNow all that's left for us to do is to load the driver manually:
sudo modprobe facetimehd
dmesg | grep facetimehd
# and now to see if the driver is actually loaded:
v4l2-ctl --list-devicesYou can see that the webcam is indeed loaded. Wonderful!
Here's how it looks like. The other folks even say that this 720p camera appears clearer than that of my daily drive machine. I don't know what to think of that but guess Apple really was in its prime.
Added 10/09/2025.
I upgraded my kernel from 6.1.0-38 to 6.1.0-39. Guess what: the facetimehd module did not get carried over. Found this out when I tried to enter a video meeting but video camera did not get detected again. Let's fix this.
First I had to make sure the video camera was still working in the first place, lest anything broke in the few days for which I was gone. Let's rebuild this module according to the original script first.
cd /tmp
git clone https://github.com/patjak/bcwc_pcie.git
cd bcwc_pcie/firmware
ls -lhaThere was no make file! Following the original script, the next step was to make here. But there was only a README that reads:
The firmware extraction tool is moved to a separate directory at: https://github.com/patjak/facetimehd-firmware
I think if my original script had failed to build this particular firmware extractor, it means I already had the necessary firmware. Let's move on then. LOL
cd ..
make
sudo make installmake -C /lib/modules/6.1.0-39-amd64/build M=/tmp/bcwc_pcie modules_install
make[1]: Entering directory '/usr/src/linux-headers-6.1.0-39-amd64'
INSTALL /lib/modules/6.1.0-39-amd64/extra/facetimehd.ko
SIGN /lib/modules/6.1.0-39-amd64/extra/facetimehd.ko
At main.c:171:
- SSL error:FFFFFFFF80000002:system library::No such file or directory: ../crypto/bio/bss_file.c:67
- SSL error:10000080:BIO routines::no such file: ../crypto/bio/bss_file.c:75
sign-file: /usr/src/linux-headers-6.1.0-39-common/output/signing_key.pem
DEPMOD /lib/modules/6.1.0-39-amd64
Warning: modules_install: missing 'System.map' file. Skipping depmod.
make[1]: Leaving directory '/usr/src/linux-headers-6.1.0-39-amd64'
SSL sign-file warnings seem harmless so I will not care about them. And depmod skipped again. Same fix.
sudo depmod -a
sudo modprobe facetimehd
v4l2-ctl --list-devicesApple Facetime HD (PCI:0000:02:00.0):
/dev/video0
Great!
Now I have to ensure I don't have to rebuild it every time I upgrade kernel in the future. Hello DKMS!
sudo apt update
sudo apt install dkms
sudo mkdir -p /usr/src/facetimehd-0.6.13
sudo cp -r /tmp/bcwc_pcie/* /usr/src/facetimehd-0.6.13/
sudo dkms add -m facetimehd -v 0.6.13
sudo nano /usr/src/facetimehd-0.6.13/dkms.confAnd overwrite the deprecated feature of MODULES_CONF that previously existed in the dated git repository:
PACKAGE_NAME="facetimehd"
PACKAGE_VERSION="0.6.13"
CLEAN="make clean"
MAKE[0]="make KERNELDIR=/lib/modules/${kernelver}/build"
BUILT_MODULE_NAME[0]="facetimehd"
BUILT_MODULE_LOCATION[0]="."
DEST_MODULE_LOCATION[0]="/updates/dkms"
AUTOINSTALL="yes"
Then adding it to DKMS should do the job:
sudo dkms add -m facetimehd -v 0.6.13
sudo dkms build -m facetimehd -v 0.6.13
sudo dkms install -m facetimehd -v 0.6.13This should fix it for future kernel versions. Hopefully.
Added 10/09/2025.
This part was surprisingly easy. First I installed fcitx5. Then I configured fcitx5. Then I went to Fcitx Configuration > Addons > Classic User Interface > Font to increase the font size because it was really small. There we go, Chinese!
P.S. I use Xiaohe Double Pinyin, btw. Configuring the input methods for that is really simple, actually:
- Add a group.
- Add the Shuangpin input method from the right column by double clicking
Shuangpinafter finding it through search. - Click Shuangpin on the left column to select it.
- Press the Settings icon in the middle
- Switch
Shuangpin ProfiletoXiaohe.
Finally I can type Chinese on the laptop after a week of having installed MX Linux. Bless.
Added 22/09/2025.
I need to be safe. Let's back up the device. For this I used a live USB stick containing CloneZilla, and I chose expert mode this time since I needed CloneZilla to help rescue if anything went wrong.
After plugging in both the CloneZilla and the storage (backup) USB sticks, I held down option while pressing the power button to boot into the live USB, as per usual procedure for the 2014 Macbook Air model, and selected the CloneZilla USB to boot into.
At the first selection menu, I used the default VGA 800x600 version of CloneZilla, with one edit: I have mentioned above that all boot parameters in GRUB needed to include intel_iommu=off in order to detect my SSD drive on this machine, so booting from CloneZilla needed that as well.
Here's the TLDR: /usr/sbin/ocs-sr -q2 -c -j2 -ntfs-ok -rescue -z9p -i 4096 -fsck-y -senc -plu -p poweroff savedisk 2025-09-21-21-img sda. Of course, I picked these options separately in the TUI mode, but this is a more straightforward way to put forth the options.
Explanations:
ntfs-ok: Skip ntfs integrity check.rescue: If disk blocks read errors, skip & continue the next one (failing SSD hence this).fsck-y: Checks & repairs file system before cloningsda: Clones/dev/sda.sda1is my root,sda2is home, andsda3should be swap.
I backed all of this up into a 128GB USB stick, which is plenty for my system since there has not been much usage in terms of storage. Thanks to using device-image backup, the size of the backup is only around 15GB. I renamed the backup folder to 2025-09-21-21-mxlinux-img so as not to confuse with my Ubuntu backup.
Wonderful.
The machine is still quite bare even after all the customisations, and I believe I will come to make many more modifications to it as I daily (or rather nightly) drive it. One day, I may get an SSD that is not starting to corrupt and transfer everything out (apparently the erosion snowballs), but that is only after I replace the battery as well. Let's not get ahead of ourselves here – this Macbook's power is still on life support. Here are some things on the future roadmap:
- REPLACE THE BATTERY
- REPLACE THE SSD
Chinese Pinyin using Fcitx (subsequently, FlyPY / Xiaohe Shuangpin)DONE!- Automation scripts?
- Power management with TLP
The computer is now capable of everyday tasks such as document editing and basic entertainment with Youtube and Bilibili, not to mention these are being done at lightning-fast speeds thanks to the XFCE desktop environment. The only pity is that there is only 4GB of memory, which is SOLDERED onto the logic board. Nonetheless, I am quite content with how this installation has turned out, and although I get somewhat sentimental thinking about the now-wiped Windows 7 system that has spent ten years with me, this breathing of new air into the Macbook Air (haha... get it...) is sure to bring us to new heights.
Arch next time, btw.
Authored 20/09/2025.
I have been typing in Chinese using double pinyin for around one or two years now. When I first started using Ubuntu, I was pleasantly surprised to find good 小鹤双拼 (Flypy / Xiaohe Double Pinyin) integration in the Rime engine. However, the word bank that came with rime seemed very small. Despite all that, I persevered and simply used the suboptimal word bank for all this while.
This time however, I got to customising the looks of my input method (because the original font size was too small), and subsequently chanced upon the community-driven project of Rime word bank expansion. WOAHH.
This was pretty straightforward. I used the GNOME Extension IBus Tweaker and edited the style settings. I increased the font size, changed up the colour, and also increased the number of phrases each page from 5 to 7. This is done through navigating to ~/.config/ibus/rime/default.custom.yaml and setting page_size to 7.
Here are my edits, with the images below showing the before & after of the customisation:
I based the Luna Pinyin Extension config file (luna_pinyin.extended.dict.yaml) off zhangheng18's rime-dict repo, but made some edits. I had also included some YAMLs from Iorest's rime-dict repo as it seemed to include more word banks. It even had an ACG word bank. Bless all contributors who made these word banks possible.
Additionally, I added my own yaml file (luna_pinyin.selfdefined.dict.yaml) to define my own terms for easy access to these words. This should be quite convenient.
Note
When defining your own dictionary, do not include any comments in the data section!
If you are expanding your IBus Rime as well, do remember to redeploy Rime either by pressing redeploy (部署) in the input method settings OR running ibus-daemon -drx. I think that redeploys as well. Do note that the first redeploy job after putting these yamls in will take a little bit of time.
Here are the exact steps I took:
- Add the
.yamlfiles into the~/.config/ibus/rimedirectory. - Configure
luna_pinyin.extended.dict.yamlto include / exclude the dictionaries you want / do not want to include. - If using double pinyin, add a
double_pinyin_(DOUBLE_PINYIN_NAME).custom.yaml. For flypy, it would bedouble_pinyin_flypy.custom.yaml. - Redeploy using
rm ~/.config/ibus/rime/default.yaml && ibus-daemon -drxand wait until the redeployment finishes.
luna_pinyin.anime.dict.yamlluna_pinyin.basis.dict.yamlluna_pinyin.chat.dict.yamlluna_pinyin.computer.dict.yamlluna_pinyin.daily.dict.yamlluna_pinyin.hanyu.dict.yamlluna_pinyin.idiom.dict.yamlluna_pinyin.name.dict.yamlluna_pinyin.net.dict.yamlluna_pinyin.selfdefined.dict.yamlluna_pinyin.sougou.dict.yaml
Here's my file structure for reference: File Structure
I'm surprised the extended dictionaries are in such a niche corner of the internet. Maybe every IBus Rime user is a power user and I am living under a rock, but now I am armed with a much larger arsenal of words.
I saw in the documentation that Rime actually supports Suzhou-Pinyin (Soutzoe) typing. One day I will learn to use it.
- https://github.com/Iorest/rime-dict
- https://github.com/zhangheng18/rime-dict/
- https://www.cnblogs.com/keatonlao/p/12983158.html
- https://blog.csdn.net/ken2232/article/details/144545853
- https://wiki.archlinux.org/title/Rime
- https://sspai.com/post/90068
- https://tieba.baidu.com/p/5602640654#
Purely for fun. Also to show off my hackerman-ness to my peers on the fly.
Authored 24/09/2025.
I chanced upon the genius iSH Project, which is:
A project to get a Linux shell running on iOS, using usermode x86 emulation and syscall translation.
Big words. All I know is that I can run a terminal on my iPhone!
- Install iSH from the App Store or the Altstore if you are feeling fancy.
- Open the app.
- Run some installation commands to install cool packages. For me, I ran:
apk add fish # fish terminal!!!!!!!!
apk add neofetch # system info (although it is really wrong for the iphone)
apk add asciiquarium # colourful ascii aquarium- Now fish needs some customisation. I modified my previous projects' fish scripts into:
config.fishas well asfish_prompt.fish, cutting out the unnecessary commands and only leaving the ones that actually work (Note:bryellowseems to break, so I changed it to justyellow). - Move these files into the
rootfolder using the iPhone native Files app. I chose to copy the text and paste them manually:
- Rename the pasted files to their correct names. I did this inside the native Files app, but you can also do it in the iSH terminal itself using
mv.
- Now, move these files from
~(which is/root, home directory, by default) to~/.config/fish(forconfig.fish) and~/.config/fish/functions(forfish_prompt.fish) separately. Create directories usingmkdirif necessary.
mv ~/config.fish ~/.config/fish
mkdir ~/.config/fish/functions
mv ~/fish_prompt.fish ~/.config/fish/functions- This sets up the fish commands nicely. Now, I also wanted fish to be the default shell, as Alpine uses
ashas the default shell. This is done through creating a.profileconfig file in~, which runs any commands inside it every time iSH boots up (and hence booting upash).
# checks for presence of "i" flag (interactive session) inside shell flags. if yes, starts fish
# because the default greeting text in iSH still shows after exec'ing fish, i also added the clear command to clear the CLI before fish starts up. hence the clear.
case "$-" in
*i*) [ -x /usr/bin/fish ] && clear && exec /usr/bin/fish ;;
esacWarning
Do not simply include exec /usr/bin/fish in ~/.profile! This will hang iSH. This means the shell doesn't care if it is in interactive mode and just goes into a loop or simply breaks.
- And here we have it! Reboot by removing iSH from background apps, and launch into iSH again.
- Date & Prompt symbol does not seem to work for the prompt function. Date is just missing, while prompt symbol defaults to
#. - On closer inspection:
echo (date "+%H:%M:%S")returns09:41when the time now for me (GMT+8) is17:41:30. Notice the seconds missing (probably an iPhone issue), and the time is in GMT. This is fixed inconfig.fishas well:set -l hour (math (date +%H) + $gmt_offset). - Most packages do not work due to lacking dependencies. This is an iPhone after all.
.profile (~/.profile)
config.fish (~/.config/fish/config.fish)
fish_prompt.fish (~/.config/fish/functions/fish_prompt.fish)
This was a very simple project, if you can even call it one. It was mostly dealing with the lack of actually-linux things on the iPhone, and wow I wonder why. Bless the developers for iSH though, one really needs to scrape the bottom of the barrel when it comes to things like this. Moving forward, I will pen more things down once I find more uses for this terminal inside my phone.
- https://ipadlinux.org/#about (I originally chanced upon this while browsing iPad linux options)
- https://github.com/ish-app/ish/wiki
- https://fishshell.com/docs/current/
- https://wiki.alpinelinux.org/wiki/Shell_management
- https://unix.stackexchange.com/a/26557
- https://unix.stackexchange.com/a/26827
























































