Trans: Latin prefix implying "across" or "Beyond", often used in gender nonconforming situations – Scend: Archaic word describing a strong "surge" or "wave", originating with 15th century english sailors – Survival: 15th century english compound word describing an existence only worth transcending.

Category: Uncategorized (Page 1 of 3)

  • This winter, I am excited to be teaching a new youth-oriented class at the Odessa Public Library- "TinkerCAD for Functional 3d Printing & Propmaking"! Sign up here:
    "Youth ages 8-18 will master the tools and skills required to design and print just about anything made of plastic, and will be confident in their ability to search for projects and models others have designed and print them at the Odessa Public Library."
  • I've been fairly distant for the last few months, but not for a lack of exciting projects! I've been sorta hyperfocused on the research and development of ultrasonically emulsified polyethylene polymers for an upcoming and very exciting material brand of my own.
  • Designed a small video light:
  • Created a overly complex rapid fab FOSH litterbox:

This and That!

updated on 5/23/22


  • Built out a lil web dashboard for DLA Makerspace- find the space's calendar, general information, technical documentation, printer livestreams for students and access the discord ticketing system-

  • I have been busy at the Ithaca Generator- building up our new website and writing new member mangegment & accounting software. I've taken over as IG's 3D Printer Area Captain too! 😸

Teaching a new class! Weekly Printer Party! Noise Night!
See a need, fill a need! An exciting new venture! Chemicals and experiments oh my!
Magic Fusion 360 for 3D Printing Class
  • Draw and print your mechanical daydreams! Watertight threads? Anneal-fit tolerances? Learn to design and print beautiful hardware and parts in this exciting workshop with Jess!
Weekly 3D Printer Party w/ Jess & whoppingpochard!

Tuesdays 5 - 8pm

Noise Night
  • Sunday nights 6pm to 8pm beginning March 20th ~~~ Come enjoy a low-key evening of casual jamming, music and noisy projects with Jess!

Some lil random printed projects:

Bits & Bobs, Mushstools & Toadrooms

...Despite being a chilly & wintery March up here in the White Mountains, there is no shortage of fun birds and exciting projects!

Merlin AI pipeline for Mushroom identification!

It's happening, and it is going to be awesome YMMV, but YOLO:

Continue reading

Chindōgu ASCII art

A ridiculous Chindōgu utility prompt & CLI for fetching private releases & files from GitHub & BitBucket

  • Fetch, unpack, extract specific releases & files or a complete master branch from a private GitHub repo with an api access token
  • Fetch and extract specific files or complete branches from a private BitBucket account with user's git authentication
  • Prefill default prompt values with a variety of console flags
  • Save & load default prompt values with a file of environment variables, see templates FetchReleasegSampleEnv_GitHub, FetchFilegSampleEnv_BitBucket, FetchEverythingSampleEnv_BitBucket, FetchEverythingSampleEnv_GitHub; pass as an argument with the -e flag, (./LeafletSync -e YourEnvFile) or provide one on launch.
curl --output LeafletSync && chmod +x LeafletSync && ./LeafletSync

Continue reading

naive distance measurements with opencv

Knowing both the Field of View (FoV) of a camera's lens and the dimensions of the object we'd like to measure (Region of Interest, ROI) seems like more than enough to get a distance.

Note, opencv has an extensive suite of actual calibration tools and utilities here.

...But without calibration or much forethought, could rough measurements of known objects even be usable? Some notes from a math challenged individual:

# clone:
git clone && cd misc-roi-distance-notes

Most webcams don't really provide a Field of View much greater than ~50 degrees- this is the value of a MacBook Pro's webcam for instance. Here's the plan to get a Focal Length value from Field of View:

So, thinking along the lines of similar triangles:

  • Camera angle forms the angle between the hypotenuse side (one edge of the FoV angle) and the adjacent side
  • Dimension is the opposite side of the triangle we are using to measure with.
  • ^ This makes up the first of two "similar triangles"
  • Then, we start measuring: First, calculate the opposite ROI Dimension using the arbitrary Focal Length value we calculated from the first triangle- then, plug in the Actual ROI Dimensions.
  • Now the adjacent side of this ROI triangle should hopefully be length, in the the units of ROI's Actual Dimension.

source a fresh venv to fiddle from:

# venv:
python3 -m venv distance_venv
source distance_venv/bin/activate

# depends are imutils & opencv-contrib-python:
pip3 install -r requirements.txt

The opencv people provide a bunch of prebuilt Haar cascade models, so let's just snag one of them to experiment. Here's one to detect human faces, we've all got one of those:

mkdir haar
wget  -O ./haar/haarcascade_frontalface_alt2.xml

Of course, an actual thing with fixed dimensions would be better, like a stop sign!

Let's try to calculate the distance as the difference between an actual dimension of the object with a detected dimension- here's the plan:


# `python3`
import math
from cv2 import cv2

DFOV_DEGREES = 50  # such as average laptop webcam horizontal field of view
KNOWN_ROI_MM = 240  # say, height of a human head  

# image source:
cap = cv2.VideoCapture(0)

# detector:
cascade = cv2.CascadeClassifier('./haar/haarcascade_frontalface_alt2.xml')

while True:

    # Capture & resize a single image:
    _, image =
    image = cv2.resize(image, (0, 0), fx=.7, fy=0.7, interpolation=cv2.INTER_NEAREST)

    # Convert to greyscale while processing:
    gray_conv = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    gray = cv2.GaussianBlur(gray_conv, (7, 7), 0)

    # get image dimensions:
    gray_width = gray.shape[1]
    gray_height = gray.shape[0]

    focal_value = (gray_height / 2) / math.tan(math.radians(DFOV_DEGREES / 2))

    # run detector:
    result = cascade.detectMultiScale(gray)

    for x, y, h, w in result:

        dist = KNOWN_ROI_MM * focal_value / h
        dist_in = dist / 25.4

        # update display:
        cv2.rectangle(image, (x, y), (x + w, y + h), (255, 0, 0), 2)
        cv2.putText(image, 'Distance:' + str(round(dist_in)) + ' Inches',
                    (5, 100), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 255, 255), 2)
        cv2.imshow('face detection', image)

        if cv2.waitKey(1) == ord('q'):

run demo with:



Client-side, asynchronous HTTP methods- TypeScript

...Despite the ubiquitousness of needing to make a POST request from a browser (or, perhaps for this very reason) there seems to be just as many ways, methods, libraries, and standards of implementing http functions in JavaScript as there are people doing said implementing. Between the adoption of the fetch api in browsers and the prevalence and power of Promises in JS, asynchronous http needn't be a hassle!

...happily processing some data in a browser, when suddenly...
you need to complete a portion of this processing elsewhere on some server...:

Continue reading

…Ever tried to Chrome Remote ➡️ Ubuntu Budgie?

Check out this project on my Github over here 🙂

Fully automated patching for Chrome Remote Desktop on Ubuntu Budgie.

Chrome remote desktop is fantastic, but often clashes with Xorg nuances from a variety of desktop environments in Ubuntu. This chrome-remote-desktop script extends and replaces the version automatically installed by Google in /opt/google/chrome-remote-desktop/chrome-remote-desktop. This stuff is only relevant for accessing your Ubuntu machine from elsewhere (e.g. the "server", the client machine should not be installing anything, all it needs is a web browser).

Set up the server:

Before patching anything or pursuing other forms of delightful tomfoolery, follow the installation instructions provided by Google. Set up everything normally- install Google's .deb download with dpkg, set up a PIN, etc.
The trouble comes when you are trying to remote in- some problems you may encounter include:

  • none of the X sessions work, each immediately closing the connection to the client
  • the remote desktop environment crashes or becomes mangled
  • odd scaling issues or flaky resolution changes

Patch it up:

# get this script:
# wget

# or:
git clone 
cd chrome-remote-desktop-budgie 

# behold:
python3 chrome-remote-desktop

# ...perhaps, if you are keen (optional):
sudo chmod u+x
sudo ./

What does this do?

We are primarily just enforcing the use of existing instances of X and correct display values as reported by your system.

  • This version keeps a persistent version itself in /usr/local/bin/ in addition updating the one executed by Chrome in /opt/google/chrome-remote-desktop/.
  • A mirror of this script is also maintained at /usr/local/bin/chrome-remote-desktop.github, and will let the user know if there are updates.
  • The version distributed by google is retained in /opt/ too as chrome-remote-desktop.verbatim.
  • Each of these versions are compared by md5 hash- this way our patched version of chrome-remote-desktop will always make sure it is where it should be, even after Google pushes updates and overwrites everything in /opt/.

This, That, etc

....Updated 07/19/2020

Bits & bobs, this & that of late:

...In effort to thwart the recent heat and humidity here in the White Mountains (or, perhaps just to follow the philosophy of circuitous overcomplication... 🙂 ) here are some sketches of quick-release exhaust fittings of mine for a large, wheeled AC & dehumidifier unit (these have been installed throughout my home via window panels).

...Sketching out a severely overcomplicated "computer shelf", rapid-fab style:
(plasma cut / 3d printed four-post server rack == RepRapRack?? xD) 🙂

...Also, Ryan @ V1Engineering recently released his new MPCNC Primo here, should anyone be keen. Long Live the MPCNC! 🙂

...Oodles of fun everyday over in the clipi project- check it out!


clipi CLI!

Find this project on my github here! updated 07/19/2020

An efficient toolset for Pi devices

Emulate, organize, burn, manage a variety of distributions for Raspberry Pi.

Choose your own adventure....

clipi virtualizes many common sbc operating systems with QEMU, and can play with both 32 bit and 64 bit operating systems.

  • Select from any of the included distributions (or add your own to /sources.toml!) and clipi will handle the rest.

clipi builds and maintains organized directories for each OS as well a persistent & convenient .qcow2 QEMU disk image.

  • Too many huge source .img files and archives? clipi cleans up after itself under the Utilities... menu.
  • additional organizational & gcc compilation methods are available in /

clipi burns emulations to external disks! Just insert a sd card or disk and follow the friendly prompts. All files, /home, guest directories are written out.

  • Need to pre-configure (or double check) wifi? Add your ssid and password to /wpa_supplicant.conf and copy the file to /boot in the freshly burned disk.
  • Need pre-enabled ssh? copy /ssh to /boot too.
  • clipi provides options for writing from an emulation's .qcow2 file via qemu...
  • well as from the source's raw image file with the verbatim argument

clipi can find the addresses of all the Raspberry Pi devices on your local network.

  • Need to do this a lot? clipi can install itself as a Bash alias (option under the Utilities... menu, fire it up whenever you want.


Shortcuts & configuration arguments can be passed to clipi as a .toml (or yaml) file.

  • Shortcut files access clipi's tools in a similar fashion to the interactive menu:
# <shortcut>.toml
# you can access the same tools and functions visible in the interactive menu like so:
'Burn a bootable disk image' = true  
# same as selecting in the interactive cli
'image' = 'octoprint'
'target_disk' = 'sdc'  
  • clipi exposes many features only accessible via configuration file arguments, such as distribution options and emulation settings.
# <shortcut>.toml

# important qemu arguments can be provided via a shortcut file like so:
'kernel' = "bin/ddebian/vmlinuz-4.19.0-9-arm64"
'initrd' = "bin/ddebian/initrd.img-4.19.0-9-arm64"

# qemu arguments like these use familiar qemu lexicon:
'M' = "virt" 
'm' = "2048"

# default values are be edited the same way:
'cpu' = "cortex-a53"
'qcow_size' = "+8G"
'append' = '"rw root=/dev/vda2 console=ttyAMA0 rootwait memtest=1"'

# extra arguments can be passed too:
'**args' = """
-device virtio-blk-device,drive=hd-root \
-no-reboot -monitor stdio

# additional network arguments can be passed like so:
# (clipi may automatically modify network arguments depending on bridge / SLiRP settings)
'network' = """
-netdev bridge,br=br0,id=net0 \
-device virtio-net-pci,netdev=net0
  • Supply a shortcut file like so:
    python3 etc/find_pi.toml

  • take a look in /etc for some shortcut examples and default values


bridge networking things:

  • working on guest --> guest, bridge --> host, host only mode networking options.
    as of 7/17/20 only SLiRP user mode networking works,
    see branch broken_bridge-networking
    to see what is currently cooking here

kernel stuff:

  • automate ramdisk & kernel extraction-
    most functions to do so are all ready to go in /

  • other random kernel todos-

    • working on better options for building via qemu-debootstrap from chroot instead of debian netboot or native gcc
    • add git specific methods to for mainline Pi linux kernel
      • verify absolute binutils version
      • need to get cracking on documentation for all this stuff

gcp-io stuff:

  • formalize & dockerfile

  • make sure all ports (22, 80, 8765, etc) can up/down as reverse proxy

# clone:
git clone
cd clipi

# preheat:
pip3 install -r requirements.txt
# (or pip install -r requirements.txt)

# begin cooking some Pi:
« Older posts