Weekly Ramblings for June 22nd, 2020

Savanni D'Gerinel 22 Jun, 2020

Hello, everyone, and welcome back after a long, unexpected hiatus!

COVID-19 has really done a number on my mental health and my activities, but I have managed to continuing to get outside to run, and nobody in my family has gotten sick. We’re continuing to largely self-isolate, with only occasional careful trips to the grocery store.

I have kept myself very busy with a combination of practicing Esperanto, trying to build a clock inside of Minecraft (harder than you might think), and building a real computer on a breadboard using real digital circuits.


This continues to be a multi-year-long project, however over the last few weeks I have participated in the Esperanto Version Fingtam Languages 30 Day Record Yourself Challenge. Turns out that this, more than anything else I have done, has helped me with my ability to speak. While I don’t participate every day, I actually have an active youtube channel. At the same time, many other people are participating in the challenge, and I believe I am starting to make friends.

Now that Evildea is also doing a series of direct method videos, I’m now immersing myself in Esperanto for a non-trivial amount of time every day, and I think that helps, too. I once watched a video talking about how language learning is mostly about input, and my biggest problem with Esperanto was the input side. There is very little media in the language and it is quite hard to find, even on Youtube. This challenge also has likely created many more Youtube streamers, which I feel is likely to be a bit self-perpetuating. I’ve been considering starting streams or videos for months, though at first I thought I would be streaming Slay the Spire or Go. However, I never did either of those and instead got myself into Minecraft.

Digital Logic Inside of Minecraft

In the early days of the pandemic, when I was really having trouble adapting to never being able to see my friends, I got a serious urge for a game that would let me just explore and build with little sense of an end of game or a particular goal. Thus, suddenly, I remembered Minecraft from long ago and decided to get back into the game. After a few weeks of playing alone, I set up a server and invited my friends to join. We had a couple of nights of mayham and fun and built out quite a lot of compound, plus I found out from some of the younger players about some higher-level automation that can be done within the game using basic components.

One of the quirks of the game is that on the first night, as we started putting up signs, I would put up signs in both English and Esperanto. In addition to Minecraft having a complete Esperanto translation, it was just fun to put up warning signs and direction signs in more than one language. And then other players started adding their own translations in French and German.

After they fell away, I moved away from the core base and started trying to decide what to build. At first, I thought a treehouse. Then I decided to revisit a long ago idea I had of building a clock that told world time within the game. Some of my inspiration comes from having read Anathem so many times, and I wanted to build a clock at the center of what could become a small compound. Or a large one. Maybe one day I’ll add a library and maybe even start writing things for books in the library, with maybe a little inspiration from certain activists who created an uncensored library in Minecraft.

But now, a month later, with many days of work into it, I continue to struggle to actually build the core clock circuit. While it’s easy to build a circuit that generates a rising pulse every second, the storage arrays tend to update much too slowly, plus I cannot figure out a design that will give me a reset line. So many things in the game might make the clock lose synchronization that I want a reset line that will force the entire clock to zero at sunrise.

My limiting factors are a combination of the size of basic logic gates (minimum of 12 cubic blocks for an AND gate, with the need to keep at least one clear block above all torches to avoid signal propogation), the propogation distance of a redstone signal (only 16 blocks), and mounting switching time. We only get 20 redstone ticks per second, and it is really surprising how quickly that can run out.

T flip-flops provide much simpler counter logic (requiring only a single AND gate between each bit) over the D flip-flop counter logic, which appears to require both an AND an an XOR gate between logic gates. At this time, I can build about a six-bit binary counter out of T flip-flops. This is enough for sixty seconds, though I still need to work out the logic for reseting these both at sunrise and at the 60-second mark. Plus, I need to send a signal to the next counter array to tell it to update, and it needs to persist until being read, because otherwise there is the chance that the signal will not last long enough to update the minute counter.

This may well be the hardest part of the whole project, even though I still have to figure out how to route the outputs into a binary decoder array, and then route those decoder outputs into a driver for a seven segment display. I know how to build both of these things, but again, signal propogation distance is really getting in the way, and the arrays themselves end up being really huge, and I need four of them for a four digit display.

This is hard enough that I keep considering giving up, especially given the next section…

Breadboard Computer

A long time ago, one of my friends told me about Ben Eater’s breadboard computer project. I pretty quickly watched the entire thing, but a month ago I finally ordered all of the parts necessary to do this project myself. Real world electronics, though they can be rather destroyed by failure to provide resistors in the right place, shorting lines, or applying current to what was supposed to be a ground line, are very small. The ones that we use in computers are impercetably small. The ones that I use in a breadboard computer are finger sized.

At this point, I have built the clock circuit, the two registers, the ALU, and assembled the memory board. So far, I have been able to understand everything, even the analog clock circuit and debouncers. As the project progresses, things are becoming a bit more abstract, where instead of laying out a bunch of 4-bit D-flip-flop chips to make memory cells, we’re actually just using two 64-bit chips that also accept address lines and do internal demuxing. Put together, I get a whole 16 bites of memory… which I will use for both program instructions and storage.

Elsewhere, we’re going to use an EEPROM to drive a trio of seven-segment displays. In one of his videos, Ben actually shows a basic logic gate layout that accomplishes the same thing, and it actually requires something like six breadboads with a lot of chips, so an EEPROM sounds like a pretty magnificent improvement over that. On the other hand, I think maybe I could do the same thing by building a binary decoder array and then feeding that into the ten lines of a matrix ROM.

This is quite fun, and I have yet to destroy anything. I have already done one video about my breadboard computer, but in Esperanto. I’m considering doing similar explanation videos with basic logic gates, and using this as fodder for additional Esperanto media to maybe inspire other people to learn the language as well!

And that is all for now! I’ll try to make these regularly again, targetting a Monday publication. Later!

FitnessTrax 0.1.0

Savanni D'Gerinel 27 Mar, 2020
The Streets at Night, 2019-09

Hello, and welcome back!

Today, I get to announce that I have release FitnessTrax 0.1!

FitnessTrax is a health and workout tracking program designed for individual users and following the privacy policy of keeping all of your data on your own computer. Data that lives there cannot be mined and exploited by third party companies that may not really have your privacy in mind.

This is the first version of the application that I feel is suitable for home users. While it is rather ugly, and limited at this time, it is also entirely usable. Over the next few releases, I plan to style the application nicely and to add many other pieces of information to the tracking system.

FitnessTrax is a GTK 3 application. It can currently only be installed from source. A NixOS derivation will be available soon. I am not currently working on installation from Crates.IO, on Ubuntu, or with Flatpack, but all three of these are on my roadmap.


This is the culmination of many years of work and learning.

I first started tracking my weight and my bike rides in 2003. I used nothing more than a couple of plain text files. For a long time, that worked, but graphs were impossible, and it was not possible for me to get a coherent view of any particular day in my history without reading information from many different places.

In 2013, I finally started trying to put all of the information into a single database of sorts. From the beginning, I had no desire to set up a separate database server. Aside from simply being overkill for an app that will only recieve a few writes every day, a separate server increases the effort necessary to install an application, and makes data backups significantly harder.

So, I started with a SQLite database and a Haskell web service. Over the years I migrated from SQLite to building an embedded time series database, then from Haskell to Haskell and Javascript, then to Rust and Javascript, Rust and Typescript, and finally to a Rust-only native GTK application.

Over the years I modified, updated, and tweaked the various data models into something that mostly fit the patterns that I could understand. I settled, at long last, on the Record data structure, then defined Weight, Steps, TimeDistance, Duration, and SetRep as records. Further, in my time at Cloud City I learned from several people who are very good at architecting user interfaces, and that has lead to the internal architecture of my application.

It may seem silly that an application that is little more than a glorified spreadsheet could take so long to build. But it should be known that I have developed this application mostly on my own, and have taken many false steps in the process. I have learned a lot, most of which I hope to one day apply to my career. I do not think that I could have ever done any better.

Saluton, kaj bonvenon reen!

Hodiaŭ, mi povas anonci, ke mi cirkuligis FitnessTrax, versio 0.1!

FitnessTrax estas sana kaj trejnada programo, ke estas konstrukcita por individua uzantoj, kaj sekvas la privatecan politikon de resti ĉion de via dateno sur via propra komputilo. Dateno ke vivas tie, ne povas esti eksplautata de kompanio, ke ne eble konsideras vian privatecon.

Tio estas la unua versio de la programo, ke mi pensas estas taŭga por hejmaj uzantoj. Dum ĝi estas malbela kaj limigita nuntempe, ĝi estas uzebla. Dum la sekvaj kelkaj versioj, mi planas bele stiligi la programon, kaj aldoni multajn aliajn datenojn.

FitnessTrax estas GTK 3 programon. Ĝi aktuale povas instalita de fonto. NixOS derivado baldaŭ estos havebla. Mi ne aktuale faras instalado de Crates.IO, Ubuntu, aŭ Flatpack, sed ĉiuj tri estas en mia plano.


Ĉi tio estas la kulmino de multaj jaroj da laboro kaj studado.

Mi unue komencis kroniki miajn pezon kaj biciklajn veturojn en 2003. Mi nur uzis simplajn tekstajn dosierojn. Tio funkcias dum longa tempo, sed estas neebla fari grafeojn, kaj mi ne povas vidi koheran bildon de unu tago en mia historio sen legi el multaj diversaj dosieroj.

En 2013, mi komencis provi meti ciun informon al unu datumbazon. Mi neniam volis agorda apartan datumbazoservilo. Krom esti tre kompleksa por programo, ke nur ricevos kelkajn skribojn po tago, aparta datumbazoservilo pliigas la penon necesan por instali aplikon, kaj malfaciligas sekurkopiojn.

Do, mi komencis kun SQLite datumbazo kaj Haskell retservilo. Dum la jaroj, mi migris el SQLite al enigita tempa seria datambuzo, tiam el Haskell al Haskell kaj Javascript, tiam al Rust kaj Javascript, Rust kaj Typescript, kaj finfine al Rust en denaska GTK aplikado.

Dum la jaroj, mi provis multajn reprezentojn de la datumoj ĝis mi havis ion, ke plejparte taŭgis la padronojn. Mi akceptis la Rekordan datumstrukturon, tiam mi difinis Pezon, Paŝojn, Tempo/Distancon, Daŭron, kaj SetRep kiel Rekordoj. En mia tempo kun Cloud City, mi lernis el diversaj uloj, kiuj estas tre bonaj pri arkitekturo, ke mi komprenis kiel konstruii mian aplikadon.

Eble ŝajnas stulte, ke aplikado kiu nur estas glorigita kalkultabelo, povas daŭri tiom da tempo por konstrui. Sciu ke mi konstruis tiun aplikadon sen helpo, kaj mi faris multajn erarojn. Mi ekkonis multe, kaj mi esperas, ke mi uzu tion en mia kariero. Mi ne pensas ke mi povis fari pli bone.

Honoring Amelia, two years later (Honoras Amelia, antaŭ du jaroj)

Savanni D'Gerinel 31 Jan, 2020

In Memory of Amelia Perry

Two years ago today, I woke up to the news that my friend, Amelia, was gone.

Amelia was the victim of our country’s transphobia and inadequate response to mental health needs. She ended her life after six months intermittently in hospitals. Since then, I have participated in some of the same hospitalization programs as her. While I have been able to recover, her experiences continue to remind me htat these systems are inadequate, and that transgender inclusion cannot be assumed even in a state whose laws support transgender rights.

My feelings are complicated. I do not feel acute pain any more, but I believe that is because I remember her, and feel a bit of pain, every single day. Every day I think about the things she could be doing, and the things she already did to advance math and science. Things that I am unable to understand because she was beyond brilliant.

So, today, we remember the anniversary of Amelia’s death and we continue to fight for the inclusion and the dignity of transgender people, and destigmatization of mental illness until it is as unremarkable as any other illness.

Hodiaŭ, antaŭ du jaroj, mi vekiĝis al la novaĵo, ke mia amiko, Amelia, mortis.

Amelia estis la viktimon de transphobia en nia lando, kaj nesufiĉa respondo al mensa malsano en nia lando. Ŝi memmortigis antaŭ ses monatoj, ke ŝi pasigis intermite en malsanuloj. Ekde tiam, mi partoprenis en iujn el la sama enhospitiligaj programoj kiel ŝi. Kvankam mi resaniĝis, ŝiaj spertoj daŭrigas memorigi min, ke iuj sistemoj ne sufiĉas, ke ni ne povas premesas transgenran inkluzon, eĉ en ŝtato kun leĝaroj, ke apogas transgenrajn rajtojn.

Miaj sentemoj estas malsimplaj. Mi ne plu sentas akran doloron, sed mi kreskas tial mi memoras ŝin, kaj sentas iom da doloro, ĉiun tagon. Ĉiu tago mi pensas pri la aferojn, kiujn ŝi povus fari, kaj la aferojn, kiujn ŝi jam faris por progresi matematikon kaj sciencon. Aferojn, kiujn mi ne povas kompreni, ĉar ŝi estis genia.

Do, hodiaŭ ni memorhonoras la datrevenon de la morto de Amelia, kaj ni daŭre batalas por la inkluzo kaj la digno de transgenraj homoj, kaj la destigmatizado de mensa malsano ĝis ĝi estas kiel neregebla tiel iu ajn alia malsano.

Rust and GTK from a React perspective

Savanni D'Gerinel 15 Jan, 2020

Recently, after a few failed attempts at using other frameworks to make an application that was both easy to use and easy to install, I embraced native software development with Rust and GTK.

Though I have made short forays in the past, GTK was a change for me. Before this, most of my user interface experience came from building React applications. The transition from React to GTK posed some challenges. Most came from differences in widget philosophy. GTK in Rust, though, is particularly hard because of the extra rules Rust enforces to protect against memory management errors and against operations that are unsafe to do in a threaded context.

In this article, I will talk primarily how I adapted the philosophies from React into GTK, and I will highlight some of the extra tricks that are necessary to make GTK conform to Rust’s rules. Rust enforces some tricky rules that will be unfamiliar to most developers, primarily in terms of how values can be shared, but also with strong restrictions on mutability. I’ll point out these rules as they come up throughout this article.

All of the examples in this article come from FitnessTrax, a privacy-first fitness tracking application. Users are able to collect fitness and biometric data in a single place on their personal computers, without depending on companies that may not appropriately protect their user’s data in the long term.

I apologize for the appearance of the application, because as of the 0.4 release I have not taken the time to learn much about how GTK handles styling. I promise that I will improve the UI significantly soon.

Some differences in framework philosophy

The developer of Conrod, a graphical toolkit for Rust that experiments with applying Functional Reactive Programming techniques to graphics programming, describes two significantly different modes for managing graphical components. In “Retained Mode”, which is the common mode for most native graphical programming, any given screen component is created, then updated repeatedly throughout its lifetime. In “Immediate Mode”, components will have a draw method in which they freshly instantiate all of their children. The framework then compares this tree to the previous tree to determine how to update the screen.

React operates entirely in Immediate mode, while GTK operates entirely in Retained mode. In web developement, D3, a popular data visualization library, also works in retained mode, and in 2018 I wrote an article about interfacing between React and D3.

React paired with Redux or Apollo-GraphQL implements some of the concepts of Functional Reactive Programming in that it automatically handles propogating data changes to components. My introduction to FRP came from Elise Huard’s book “Game Programming in Haskell”. This book may be getting out of date by this point, but it does serve as a good introduction to the concept in the context of a particular FRP library in Haskell. Unfortunately, FRP has not seen wide adoption outside of React. Though there is at least one FRP library available for Rust, at the time of this writing it feels a bit too immature for me to adopt. As such, with a bit of creativity and my experience with React, I have designed mechanisms that approximate the FRP paradigm.

A note on terminology:

  • A widget is a GTK object which represents something on screen. This could be a Window, a Button, a Label, or a Layout container. GTK widgets can only have other GTK widgets as their children.
  • A component is any logical abstraction of a section of the screen. In simple cases, this will be a GTK widget returned from a function. In more complex cases, it may be a structure which contains one or more widgets. Components cannot necessarily be passed into GTK functions. Structure components always provide a public widget field which represents the root widget for this component.

An immutable value display

The simplest of all components is, much like a React component, a small collection of widgets that gets created and then never gets updated. This can be implemented simply as a function that returns a GTK widget.

A simple display showing the date January 13, 2020

pub fn date_c(date: &chrono::Date<chrono_tz::Tz>) -> gtk::Label {
    gtk::Label::new(Some(&format!("{}", date.format("%B %e, %Y"))))

This pattern works when a component really is meant to be a visual component that rarely, or even never, updates. In my application, date labels are subcomponents of larger displays, and thus are the kind of thing that never change.

A component with internal widget state

Components with internal widget state only can be significantly more complex, yet can still be implemented as a function which returns a GTK widget. The the caller could read the data directly out of the returned GTK widget, this pattern arguably works best when the caller supplies a callback, and the component encodes rules for when to call the callback.

I have a validated text entry field. It is a regular gtk::Entry, but the interface abstracts the text handling behind render, parse, and on_update functions.

Two text entry fields. The one on the left shows an orange border to indicate that the value "15.abc" is not valid as a distance. The right one has a black border to indicate that "1:15:00" is a valid duration.

pub fn validated_text_entry_c<A: 'static + Clone>(
    value: A,
    render: Box<dyn Fn(&A) -> String>,
    parse: Box<dyn Fn(&str) -> Result<A, Error>>,
    on_update: Box<dyn Fn(A)>,
) -> gtk::Entry {
    let widget = gtk::Entry::new();

    let w = widget.clone();
    widget.connect_changed(move |v| match v.get_text() {
        Some(ref s) => match parse(s.as_str()) {
        None => (),


The caller must provide an initial value, a render function, a parse function, and an on_update function. In my implementation, the validated text entry will attempt to parse the string within the box after each change, and will call the on_update function only if parsing succeeds. The caller is thus responsible for saving the data, but does not have to worry about the mechanics around parsing or verifying that it has valid data.

I find this pattern particularly useful in forms where I opt to store all of the values of a form together in one place. Storing all of the data together lets me notify the user immediately of errors, lets me detect errors that occur as a result of invalid combinations of data, and lets me easily disable the Submit button when there are errors present.

Components with internal state

2020-01-31: it turns out that I have made some big mistakes in the code in this section. I will need to revise it pretty significantly to handle more efficient component updates, and changing component state in a GTK callback.

While I build my application out of simple components like those above, I put them together into more sophisticated components that have multiple pieces of data that logically belong together but mechanically get edited within the various subcomponents. For this, I set up an internal state independently of the state of the subcomponents.

Fortunately, I can still usually implement this as a function.

Take the instance of a bike ride, which I have abstracted to a “time/distance” record. A time/distance event has a start time, an activity type (bike ride, walk, run, kayak trip…), a distance, and a duration. My user interface binds all of these together into a single component that worcks on the entire record at once.

An edit interface for information about a bike ride. It is a single row containing the time of day that the ride started, a dropdown menu in which Cycling is currently selected, a distance of 15.5km, and a duration of 1 hour, 15 minutes.

pub time_distance_record_edit_c(
    record: TimeDistanceRecord,
    on_update: Box<dyn Fn(TimeDistanceRecord)>,
    ) -> gtk::Box {

Here we start to run into the rules that Rust enforces to guarantee safe memory management.

Every value has exactly one owner. While you can get a borrowed reference to that value, those references must go out of scope before that value’s owner goes out of scope. Additionally, you can only get a mutable reference if there are no other references of any kind. The Rust Book talks in detail about these rules and provides a significant number of examples and scenarios.

Fortunately, all of the parts are already here. I need a way to share the record across multiple callback functions, and I need a way to ensure safe multithreaded access to the record. We solve the sharing problem with an Arc. This is a thread-safe reference counted container. Any value passed to the Arc’s initializer becomes owned by the Arc. Cloning an Arc increments the reference count and creates a second reference that points to the shared value.

Arcs do not allow mutable access to the values they contain, so we need to also include an RwLock. As expected, an RwLock allows many readers but only a single writer, and no readers are allowed when there is a writer. So, here is how we safely mutate the record:

pub time_distance_record_edit_c(
    record: TimeDistanceRecord,
    ...) -> gtk::Box {

    let record_ref = Arc::new(RwLock::new(record));

        let mut rec = record_ref.write().unwrap();
        ref.activity = Cycling

Within the sub-block of code, rec becomes a mutable reference to the record data. RwLock governs read/write access to the data, while Arc allows the data to be shared across functions or even threads.

Putting it all together, our code looks like this:

pub time_distance_record_edit_c(
    record: TimeDistanceRecord,
    on_update: Box<dyn Fn(TimeDistanceRecord)>,
) -> gtk::Box {

    let on_update = Arc::new(on_update);
    let record = Arc::new(RwLock::new(record));

    let duration_entry = {
        let record = record.clone();
        let on_update = on_update.clone();
        let duration = record.read().unwrap().duration.clone();
            Box::new(move |res| match res {
                Some(val) => {
                    let mut r = record.write().unwrap();
                    r.duration = Some(val);
                None => (),

(note: functions are always read-only and so require only the Arc for sharing)

To recap, in the above function, we have a block of code which clones the Arc containing the record. That clone gets moved into the callback function for duration_edit_c (meaning that the callback function now owns that particular clone). Within the callback funuction, the record will be borrowed mutably, updated, the data cloned and passed to on_update, and then the write lock will be automatically dropped at the end of the block.

This is a lot to absorb all at once. If you are not familiar with Rust, I definitely recommend reading about the ownership and borrow system, which is the magic that takes memory management away from the developer without incurring the cost of a garbage collector.

Updating from system state changes

Finally, the fourth pattern covers all components that need to respond to system changes. In React terms, this means property changes, possibly from Redux.

At a high level, we need a struct which keeps track of all of the visual components that may be updated given new data, and a render function which will handle those updates and return the root level widget.

For this example, I provide my History component.

An image illustrating the main health history interface. The left side contains two buttons, one atop the other, labelled with January 6, 2020, and January 13, 2020. To the right side are day entrcies for January 13, 2020 and January 12, 2020, with a variety of components within each.

struct HistoryComponent {
    widget: gtk::Box,
    history_box: gtk::Box,

pub struct History {
    component: Option<HistoryComponent>,
    ctx: Arc<RwLock<AppContext>>,

impl History {
    pub fn new(ctx: Arc<RwLock<AppContext>>) -> History { ... }

    pub fn render(
        &mut self,
        range: DateRange,
        records: Vec<Record<TraxRecord>>,
    ) -> &gtk::Box { ... }

The constructor here is actually quite simple, doing nothing more than creating the abstract History component. It doesn’t even create the widget at this point, as it has no data to populate into the widget. This is rather convenient because at construction time components may require data that is not available yet.

The bulk of the work appears in render:

    pub fn render(
        &mut self,
        range: DateRange,
        records: Vec<Record<TraxRecord>>,
    ) -> &gtk::Box {
        match self.component {
            None => {
                let widget = gtk::Box::new(gtk::Orientation::Horizontal, 5);

                /* create and show all of the widgets */

                self.component = Some(HistoryComponent {

                self.render(prefs, range, records)
            Some(HistoryComponent {...}) => {

If this is the first call to render, the visual components will not exist yet. Render will create all of the components, and then call itself again to populate them with the data.

    pub fn render(
        &mut self,
        range: DateRange,
        records: Vec<Record<TraxRecord>>,
    ) -> &gtk::Box {
        match self.component {
            None => {
            Some(HistoryComponent {
                ref widget,
                ref history_box,
            }) => {
                history_box.foreach(|child| child.destroy());
                records.iter().for_each(|record| {
                    let ctx = self.ctx.clone();
                    let day = Day::new(
                    history_box.pack_start(&day.widget, true, true, 25);

On subsequent calls, render will handle updating the widgets. The details of how to populate the new data will vary pretty significantly by component. In this case I destroy all of the existing subcomponents and create new ones based on the data that I have. This is a pretty naive strategy, but sometimes it works.


And so, here they are. Four high level patterns that I discovered through weeks of learning how to program GTK. I doubt that this will be their final form.

Even over the course of writing this article I significantly modified, refactored, and simplified my components. I imagine that these four patterns will take me very far in this application, while also expecting to learn much more as I proceed.

A bit of freehand sketching

Savanni D'Gerinel 14 Jan, 2020
A very rough sketch featuring several plain squares with some rough perspective. The sketch represents my living room. There is a dark square in the center representing my TV, with multiple arches representing the various openings in the wall.

As a change of pace, today I’ll share a rough freehand sketch that I made this morning. I was sitting in my favorite spot in my living room and decided to do a quick fifteen minute “speed sketch”. This one depicts my TV, the stand it sits atop, and the various doorways leading out of the room. It basically skips out on all of the details sitting around.

I was good at sketching back in high school when I took a semester-long class of it, but I’ve largely stopped doing it. However, my partner has decided to start sketching as a way of driving her artwork, and I just added wireless capability to my wacom tablet, so I’ve suddenly decided to do some of the same. Though perhaps not at the one-a-day rate that she’s going for.

Art is something I’ve been neglecting, and I note that I don’t think I have taken one single photograph with my good camera yet this year.

So, in penance, I will share a phone photo of Sapphira looking all comfortable.

A white cat with sapphire-blue eyes and black ears. She is looking at the camera with only her head visible as the rest of her body is underneath a red comfortor. She appears very comfortable.

Dreamer, Shaper, Seeker, Maker