Litographs
Python / JavaScript / Liquid / Airtable
In 2013, I co-founded Litographs, a literary gift company that makes art from books. I went through Techstars Boston in 2014 as COO. In 2018, I took over as CEO.
I taught myself Python early on, and throughout the past decade I have continuously expanded my programming skills. In my 10+ years at Litographs, I developed new products, partnered and integrated with a nationwide network of printers, managed employees, and built and maintained critical systems for the business. I’ve detailed many of these systems on this page.
Litographs creates art from books.
From a distance, each Litographs design depicts a scene, character, or theme of a book. Move closer, and you can read the book itself.
Our current collection includes over 350 titles, including around 100 licensed, contemporary works. Every title now includes a full product line of ten product types, with several size and color options for each product.
Building Litographs Systems
In my time at Litographs, I have built and maintained systems that are critical to the business’s function and success. I’ll describe some briefly here, and then below that, I’ll go into more detail on a few specific systems. For most of these I can’t share the code itself here, but would be happy to go into more detail in person.
The scripts/systems above are just a short list of examples to illustrate the type of development and problem-solving work that I’ve done for Litographs. I have also built and maintained many other systems and written hundreds of one-off scripts to automate other tasks as they arose, working with a variety of APIs and libraries.
For the four systems below, I’ll go into more detail.
Wholesale Commissions
While most of Litographs’ sales are direct to consumer, we also sell to bookstores and gift shops throughout the country. We take sales directly by email (and then send an invoice via Zoho) or on an online wholesale marketplace called Faire. We have two groups of sales reps, with each rep covering distinct territories. Our contract with each rep group requires us to send detailed commission reports monthly, along with order details (invoice PDFs, for orders placed directly; and custom-generated order detail spreadsheets, for orders placed on Faire).
We run wholesale_commissions.py from a Bash instance in Pythonanywhere. I chose this script to run through because it is self-contained and doesn’t have any sensitive code or information (the commissions rates and names of the reps / rep groups have been changed for the version below).
The previous method for calculating commissions and sending these reports was very time consuming — downloading invoices/orders from the Zoho/Faire portals, reformatting in Excel, copying over formulas from previous months, etc. As a monthly task, it was a good candidate for automation. Now, it takes no more than 5 minutes each month to run the script, enter the payments due, and email our reps.
Sales Projections Model
Litographs produces almost everything on-demand. In November/December, our order volume often increases past our typical production capacity. I built our Sales Projections system in order to accurately predict sales and communicate that to our printing partners, so that they have enough notice to scale up their production capacity. That’s something they can’t do overnight — they need to find reliable temp work for those two months, and vet/train those people well ahead of the holiday rush.
Also, though Litographs doesn’t typically hold much printed inventory, we do need to purchase blanks (blank t-shirts, blankets, etc.) ahead of time. We don’t want to be left with too much on hand in January, and we especially don’t want to run out of any blanks during the holiday rush. Our projections model feeds into our blanks inventory model to help us meet those goals.
Our sales projections are stored in Airtable. Since I can’t share exact figures, I’ll lay out some of the fields, where figures for past data are pulled from, and how future figures are calculated.
There is one record for each day of the year. All values in records with dates today or later are projections; all values in earlier dates reflect actual data.
I set up this system so that it can be completely hands off, and still serve as a useful forecast. Every day, actual data populates the table, and new projections are calculated based on the updated data. A python script runs daily in the early morning, as a task in Pythonanywhere.
But it is also built to be easily tweaked as we see trends develop throughout the year / season. The “multiples” we can input are granular, so we can quickly play around with exactly how an uptick in Ad Spend would impact overall revenue, or how a shift in the popularity of a given product type can impact that product type’s unit sales. Before I built this system, trying to predict any of these figures felt imprecise at best, and arbitrary at worst.
And as mentioned above, these projections impact several critical business decisions, from scaling up production capacity to ordering blanks far in advance. The following section details the system I built to track our Blanks Inventory.
Blanks Inventory Management
As mentioned above, while Litographs does not hold much printed inventory, we do buy blanks in advance — blank t-shirts, blankets, scarves, puzzles, etc. We then print on those blanks as the orders come in.
Holding blanks inventory as a highly seasonal business presents several challenges. The projections system that I built and detailed above solves one challenge — the projected unit sales for each product type dictate how many blanks we expect to use on any given day throughout the year. We also need to be able to accurately track how much inventory has been used, and alert ourselves when the inventory goes below a certain threshold — and each type of product’s blanks come from a different source, with different lead times.
Our Blanks Inventory is stored in Airtable, with one table for each product type. I’ll use t-shirts as an example here, but the system I built works the same for all other product types. Each size t-shirt has its own record. Blanks Remaining is calculated as:
(Last Inventory Count) + (Blanks Ordered Since) - (Tees Sold + Reprints + Defects + Other Spoilage Since) - (Tees in Open Orders)
Tees in Open Orders is updated by a script in Pythonanywhere hourly — during the holiday rush, this ends up being important so that we can be alerted in time to mark a size or product out of stock.
Tees Sold, Reprints, and Defects are calculated in a separate script that runs daily in Pythonanywhere. It looks at our historical production data and sums those values since the date of our last inventory count. This same script also looks at our T-Shirt Unit Sales projections (as reviewed in the section above) to project the number of shirts that will be remaining for each size at given intervals (14 days, 30 days, end of year, and a “given date” which we modify as needed throughout the year). To project those sales per size, the script first determines Size Percent based on sales data from the past month, then applies that percent to the sum of all T-Shirt Unit Sales projected in the given period.
For each product type, a “Running Low” view in Airtable populates based on rules we set depending on the product type. When any products/sizes enter that view, it triggers an email alert to review blanks inventory and take some action, like ordering more blanks or (hopefully not) marking a size out of stock.
This system, in combination with the Sales Projections Model, allows us to confidently purchase blanks inventory well in advance and avoid running out when demand is high during the holiday rush.
Automating Photoshop — Generating Art and Mockups
In the sections below, I’ll walk through the process of generating art and mockups, using the design for a book called “Gilded” as an example — here is the full collection of products for that title.
Generating Art
Generating Mockups
Management
In 2019, I shifted my focus away from growth and over to streamlining the business for profitability. That meant automating everything to the point where I could step away completely and leave the day-to-day work to our one remaining employee.
But in my growth-focused years as CEO, I managed three employees — a COO, Head of Community, and Head of Product/Software. I oversaw all of their work (including code review), planned/prioritized team projects in Asana, and had weekly one-on-ones.
Operations
Printing on demand is a logistical challenge. For the last decade, I have managed Litographs’ production.
A big part of Litographs’ production management is in our supply chain. I’ve sourced blank t-shirts and materials for scarves, blankets, and more (as mentioned in the Blanks Inventory Management section above). I’ve developed relationships with several vendors and distributors, shipping to printing partners around the country.
That network of printers helps Litographs scale up production at peak times and de-risk the on-demand printing process. With a short peak season (Black Friday through Christmas), it’s critical that we have contingencies if one printer falls behind.
Managing Litographs' production has given me a unique perspective on systems design as a whole. Going from a blank t-shirt at a factory to a finished product at a customer’s doorstep requires much more than just software — it requires relationships, organization/planning, the ability to decide what’s critical (and what’s not), and much more.