Building a Flutter app, part 3: navigating between app screens using routes and

Welcome to part 3 of my Flutter App development journal!

In this post: Building more pages for the app, linking them together so the user can “click around” and navigate between the different screens.

To view the project repo as it was during this step, click here.

Making the list items respond to taps

In Part 2 we left off with a main screen that displays some mock data and can be scrolled, but nothing really goes anywhere or does anything yet. Making the list items interactive is the next step. The ListTile class already supports an onTap property, so adding that is easy.

Here’s some basic “wiring” that causes tapping on any of the list items to trigger a function I added called goToStub.


goToStub(destination) {

Widget build(BuildContext context) {

itemBuilder: (BuildContext context, int index) {
  if (index == list.length) {
    return ListTile(
        title: Text("Add new " +  listType  + "..."),
        onTap: () => goToStub("Going to: Add new " + listType),
  } else {

Be sure to give the onTap an anonymous function structured like this:

onTap: () => goToStub("string here") 

instead of a function call this:

onTap: goToStub("string here")

If you do the latter, it’ll cause goToStub(...) to get called immediately on page load. This doesn’t “do” anything yet, it’s just a print statement that proves the wiring works. Now that we know it works, we can build a second page and make it so the onTap takes you there.

To see the complete code example for the onTap and stub function wiring, take a look at this commit.

Navigating between different pages in the app

In this step, I’ll make it so tapping a list item opens a different page in the app.

There are at least four different user flow “paths” out of this main page:

  • Tap a shopping list => open that shopping list
  • Tap a store => open that store’s management page
  • Tap “Add a new shopping list…” => take the user to a form where they can add a new shopping list
  • Tap “Add a new store…” => open a form where the user can enter a new store

I’m going use mock data for these UI pages; I think building the UI will make it easier to determine the data structures.

Building the ‘Add new shopping list’ page UI

First, I created a views folder and added a new file within: views/new_shopping_list.dart

import 'package:flutter/material.dart';

class NewShoppingList extends StatefulWidget {

  static const routeName = 'newShoppingList';

  NewShoppingList({Key key});

  _NewShoppingListState createState() => _NewShoppingListState();

class _NewShoppingListState extends State<NewShoppingList> {

  void saveList(BuildContext context) {
    print("Saving new list");

  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Add new shopping list"),
      body: Center(
        child: Padding(
          padding: EdgeInsets.all(20),
          child: Column(
            children: [
                autofocus: true,
                decoration: InputDecoration(
                    labelText: 'Shopping list name',
                    border: OutlineInputBorder()),
                onPressed: () => saveList(context),
                child: Text('Save'),
  • It is a stateful widget because the user is going to interact with it and it has a very simple “saveList” method that doesn’t do anything except send the user back to the main screen.
  • I defined the name of this route near the top, look for static const routeName = 'newShoppingList';
  • I wrapped everything in a Padding widget because without it, the text field was right up against the screen edges.
  • There’s a lot more to do to make the form actually work, but I just wanted to build the UI and wire it all together before getting into that stuff

Next, I went back to main.dart and above the MaterialApp return added a routes object. This is the same pattern Flutter’s docs teach.

class MyApp extends StatelessWidget {

  Widget build(BuildContext context) {

    var routes = {
      NewShoppingList.routeName: (context) => NewShoppingList(),

    return MaterialApp(
      routes: routes,
      theme: ThemeData(
      home: MyHomePage(title: 'Grocery Go!'),

Finally, in main_screen_list.dart I changed the onTap to call a new method I added to the file called goToNew.

onTap: () => goToNew(context, listType),
goToNew(context, destination) {
  if (destination == 'shopping list') {
    Navigator.pushNamed(context, 'newShoppingList');

I pass it listType, which isn’t ideal because it’s just a string that looks like “shopping list”, but for this first pass implementation I didn’t want to do anything more than just what was needed to illustrate how this works. We will refactor this soon.

You can see all of those changes in this commit.

Here’s what we have now. Note that it doesn’t actually save “New list”, it just sends me back to the main page.

Building the ‘Add new store’ page UI

The ‘add a new store’ page is very similar to the ‘add a new shopping list’ page, so I copied and pasted the contents of new_shopping_list.dart into a newly created file, new_store.dart and built it out from there. I also updated the routes object to contain the new route in main.dart:

var routes = {
NewShoppingList.routeName: (context) => NewShoppingList(),
NewStore.routeName: (context) => NewStore(),

You can see all of the code for new_store.dart in this commit.

The result:

We will come back to this page later to hook it up to a mapping API for choosing the store location, but for now this is enough to get the route wired in.

Building the ‘Shopping list’ page

This page is where the user sees what’s on a specific shopping list, adds and removes items to the list, and manages the list itself. Unlike the “create new…” routes I made earlier, this route is going to need some data passed into it when the user navigates to it. The Flutter documentation has a great guide for passing parameters into a route.

My new route takes a listID and a listName. (I may refactor this to be a single list object later on that contains these things as properties but for now I’ll just go with passing in these two things separately.)


class ExistingShoppingListArguments {
  final String listID;
  final String listName;
  ExistingShoppingListArguments(this.listID, this.listName);

class ExistingShoppingList extends StatelessWidget {

  static const routeName = '/existingShoppingList';

  Widget build(BuildContext context) {

    final ExistingShoppingListArguments args = ModalRoute.of(context).settings.arguments;

    // now I can do stuff with args.listID, args.listName

    return Scaffold(

The “existing shopping list” page is similar to the main page in that it’ll be two lists in a column together, where the top list is the “active” part of the list, sorted by category and the bottom list is crossed off items.

return Scaffold(
  appBar: AppBar(
    title: Text(args.listName + ", id: " + args.listID),
  body: LayoutBuilder(
    builder: (BuildContext context, BoxConstraints viewportConstraints) {
    return SingleChildScrollView(
      child: Column(
        mainAxisSize: MainAxisSize.min,
        mainAxisAlignment: MainAxisAlignment.start,
        children: <Widget>[
          ItemListHeader(text: "Category/Aisle here"),
          ItemList(list: list, listType: 'item'),
          ItemListHeader(text: "Crossed off"),
          ItemList(list: crossedOff, listType: "crossedOff"),

Refactor notes: I renamed MainScreenList to ItemList and MainScreenListHeader to ItemListHeader, added an Item model, and expanded the listType handling to vary what is displayed for a single Item based on what kind of item it is.

Here’s where we’re at now, after this code was merged in:

I also added two new libraries to the project for date parsing:

These refactors and additions can be found in this pull request. (I’m switching to pull requests instead of individual commits now that the work for each step is getting more complex.)

Building the ‘Store details’ page UI

This is the page where the user edits an existing store.

I rolled the code for this one into the previous pull request, look for views/existing_store.dart to see how I built this one and how I pass in an existing store for editing.

(Editing a store doesn’t do anything yet, this is just more UI work.)

Now the user can tap around and change what page of the app they are on!

Routes and UI for adding and editing list items

There are just a few major routes left to build:

  • adding a new list item
  • editing an existing list item
  • user account stuff – I’ll save this stuff for later

Adding a new item

Items are individual things (“eggs”, “bread”, etc.) on the shopping lists. To keep the adding of new items quick and easy, the user only needs to enter the item’s name to add it to the list.

For now, the new_item.dart page is simple:

Later this will be expanded to running a real-time search on the user’s existing items so the user can quickly pick an existing item with a similar name instead of entering a brand new item every time they want to add “milk” to the list.

Something to note on this route is that the listID is passed as an argument. This is so the newly created item can be assigned a list when it is created. It uses the same “how to pass an argument to a route” pattern described here in the Flutter docs.

Editing an existing item

When viewing an item in the list, the little “i” icon on the right can be tapped to open up the item’s details.

(For now, tapping the item name itself will cross the item off the list. I don’t know if I like this particular UX – I keep tapping the item name hoping to edit it, only to remember I need to tap the “info” icon to edit it. This is good enough for now, though.)

Tapping the “i” opens up existing_item.dart where the user can modify any of the item’s properties, including:

  • name (such as “eggs” or “cut frozen green beans”).
  • quantity, which is an int for now but may be expanded into a more descriptive set of options later on.
  • private (boolean), which makes it so this item only shows to the person who added it to the list, so something like “cake for surprise party” isn’t visible to everyone else who has access to this list.
  • “okay to substitute” (boolean), which flags whether the shopper should attempt to buy a different item instead
  • a list of suitable substitutes, as well as an option for “any” (or some other way to communicate “not picky”)
  • urgent (boolean) for marking items as high priority
  • an item belongs to one user-defined category
  • an item belongs to at least one list

Most of this data is optional. The intention is that the user will create an item quickly then refine it over time, especially for recurring items. The substitution information is to help people in the same household communicate brand preferences to whoever is actually at the store to help cut down on real-time texting and confirming of item choices.

Now we have this:

Passing the item data into existing_item.dart is handled around line 97 in item_list.dart:

gotoExistingItemManagement(context) {
  if (listType == 'shopping list') {
    print("opening page: manage existing shopping list");
  } else if (listType == 'item') {
    Navigator.pushNamed(context, ExistingItem.routeName, arguments: ExistingItemArguments(item));
  } ...

ExistingItem is stateful, so the initial code structure should look familiar by now:


class ExistingItemArguments {
  final Item item;

class ExistingItem extends StatefulWidget {
  static const routeName = '/existingItem';
  ExistingItem({Key key});

  _ExistingItemState createState() => _ExistingItemState();

class _ExistingItemState extends State<ExistingItem> {

The tricky part was getting this stateful widget to use the item parameters that were passed to it.

This page is for editing an existing item, so I want to populate the form fields with its existing data, but I also want the user to be able to edit that data.

The first thing I added was “local” copies of the variables that will come in with the “args”.

class _ExistingItemState extends State<ExistingItem> {

  String _name = 'ERROR: ARGS NOT LOADED!';
  int _quantity = 0;
  bool _subsOk = false;
  bool _urgent = false;
  bool _private = false;
  ExistingItemArguments args;

Then, inside the Widget build(...) stuff, if args is null (they haven’t been loaded in yet), set args equal to the args that came in from the route.

Widget build(BuildContext context) {
  if (args == null) {
    args = ModalRoute.of(context).settings.arguments;

(See the official docs for more info on ModalRoute.of(context).settings.arguments)

Now we have a bunch of pages that are wired together, passing and displaying mock data:

Here is the pull request that finishes up this work by making the “edit existing item details” page elements functional.

You may also like to browse the repo at this point in development.

Up next in Part 4: refining the mock data, building components for repeated code, and improving the ways data gets passed around.

React – Using the useMediaQuery hook to make the number of columns in a Material UI GridList responsive

In this short tutorial: How I used React’s useMediaQuery hook to make the number of columns in a Material GridList responsive.

Let’s say you’re using Material UI’s GridList, but you want the number of columns it uses to change depending on how wide the user’s screen is, like this:

Poking around the API reveals that you can set the number of columns by setting the col property to a value, but it doesn’t say how to make it responsive.

If you Google this problem, you might come across this StackOverflow post where the top-rated reply suggests using withWidth, but the React docs have widthWidth tagged as deprecated.

Instead, they point you at the useMediaQuery hook, which is what my example will use.

Being somewhat new to React hooks, my first instinct was to put this logic into a function but React didn’t like that. The useMediaQuery hook has to sit inside the functional component, and not inside a useEffect, or a function, or any of the other things I thought I should reach for. Also, it returns a boolean, so it’s better to think of it as setting a flag that you then check somewhere else.

Eventually, I arrived at this approach which sets a series of flags to true/false and then checks them to determine how many columns to use:

import React from 'react';
import { useTheme } from '@material-ui/core/styles';
import useMediaQuery from '@material-ui/core/useMediaQuery';

interface IInbox {
  posts: Array<Post>; // array of type "Post"

const Inbox: React.FC<IInbox> = ({ posts }) => {

  const theme = useTheme();

  const screenExtraLarge = useMediaQuery(theme.breakpoints.only('xl'));
  const screenLarge = useMediaQuery(theme.breakpoints.only('lg'));
  const screenMedium = useMediaQuery(theme.breakpoints.only('md'));
  const screenSmall = useMediaQuery(theme.breakpoints.only('sm'));
  const screenExtraSmall = useMediaQuery(theme.breakpoints.only('xs'));
  const screenNarrow = useMediaQuery('(max-width:340px)');

  const getScreenWidth = () => {
    if (screenExtraLarge) {
      return 6;
    } else if (screenNarrow) {
      return 1;
    } else if (screenLarge) {
      return 5;
    } else if (screenMedium) {
      return 4;
    } else if (screenSmall) {
      return 3;
    } else if (screenExtraSmall) {
      return 2;
    } else {
      return 3;

  // note: I skipped some of the structural elements of my return statement to focus on just what's relevant to this example

  return (
    {posts.length === 0 &&
       <span>No posts!</span>

    {posts.length > 0 &&
       {, index: number) => (
           onClick={() => pressEnvelope(post)}
           rows={1.25} >
             <img src="path/to/image.png"/>
               title={"From: " + post.from}
         ))} // closes .map 

export default Inbox;

As the screen is resized, the col property runs the method and gets the correct number of columns to use.

If I find a more elegant way to do this I’ll update this post, but in the meantime, I hope it helps someone else on their journey with React useMediaQuery!

2019 Learning Recap

As we say goodbye to 2019, I wanted to make a little record of some of the cool things I worked on and learned this year.

I made a web app in React!

I’m very far from a React expert, but I really wanted to at least get my feet wet (kiddie pool, not ready for the ocean yet) in it because React is so popular.

Looking back on this project, I wish I’d documented my trial and error, but it was a lot of trial and error – I’m nowhere near ready to write a tutorial on it.

I used React to build a webapp that checks a blog post you give it for defunct Amazon links:

It scrapes the post you give it for Amazon links and feeds them through Amazon’s advertising API to see if a product comes back or not. If a product does not come back, the link is marked as suspicious in the report it generates. (Some products exist on but are not in their API for some reason – so it does generate some false negatives. Hey, it still beats manually clicking each link.)

It’s live – I deployed it to a free Heroku server (hence the slow startup).

I got my start in web development setting up and running affiliate marketing blogs, and I always thought it’d be neat to have a tool that can check for dead links instead of periodically clicking them all myself.

You have to be an established affiliate with Amazon with at least a small amount of monthly sales to get access to their product API, so I made a video demonstrating how it works for those who don’t have credentials and/or just want to see it in action.

The biggest thing I got out of this project was the experience of revising my initial approach several times. My initial idea was to scrape the blog post for Amazon links, then basically run automated tests on each link to see if an Amazon page loaded and scraping it for data to determine if the product is actually there. Whoops – Amazon does not like being scraped. They direct you towards their API instead, which was a whole new project-within-a-project.

There were many times during this tool’s development where I hit a wall and thought I’d abandon it, only to have an idea later that day for working around whatever limitation I was up against.

I made my first WordPress plugin!

I started using WordPress way back in 2013. I have lots of experience using plugins, but I’ve been frustrated and disappointed in many of them – they just didn’t do quite what I wanted, or they had an overwhelming amount of options that I didn’t need, or they were too expensive.

This year, I decided to stop being intimidated by the idea of building my own and made a very simple (okay, it wasn’t simple, but it looks simple when it’s on the site) “product box” plugin. I documented the entire process in a series of detailed TILCode posts, starting here. I learned a lot from making this, and – most importantly – I realized I’ve finally skilled up enough to take on a novel challenge and carry it through to completion.

You can see its repo here: and download it if you want to use it.

I completed five classes towards my CS degree!

I’m almost done! I’m on track to graduate in June of 2020.

I completed nearly 1/3rd of my degree this year. I took:

  • CS340 – Intro to Databases – basically “web dev, part 2” on a somewhat dated tech stack that didn’t go as deep into SQL as I’d hoped it would
  • CS344 – Operating Systems – a challenging class that deepened my understanding of bash, Linux, and sockets through four large projects
  • CS475 – Parallel Programming – a great class on an intimidating topic I’m not sure I would have studied on my own
  • CS372 – Intro to Networking – an incredibly detailed deep-dive into the inner-workings of the Internet, there’s no way I would have slogged through all those calculations on my own
  • CS362 – Software Engineering II – lots of automated testing practice that, unfortunately, left out a lot of standard industry tools and best practices

A common theme to the classes I took this year was “stuff I don’t have much experience with and probably wouldn’t have done on my own”.

One of the most valuable things about this degree program, to me, as someone who already has some professional programming experience, is when it exposes me to things I would not have found (or pushed myself through) on my own.

Some of these classes were very much outside my experience and quite challenging, particularly operating systems and networking. I appreciate learning about these things in a structured academic setting as opposed to on the fly at a job where people are counting on me to already know the basics.

I am still very happy with my choice to attend OSU. I’ve learned so much.

Here’s to a wonderful 2020!

Building a WordPress “product box” plugin, part 3 – refactoring

Part 1 – Initial idea, design, and first-pass implementation
Part 2 – Building the product box that gets displayed in posts
Part 3 – Refactoring the codebase into classes, views, and separate files
Part 4 – Adding image uploading, shared plugin options, and uninstallation

Day 8: Refactoring the plugin’s management page with WP_List_Table

I did some soul-searching and realized that while I was happy with what I’d built so far in Part 1 and Part 2, it wasn’t very ‘standardized’. In other words, I had finally learned enough to want to scrap it all and start over.

I’m glad I did – and while it took some effort, it was worth it in the end.

In which I keep what I’ve learned so far but throw out the code and start over.

Using WP List Table for a standard-looking admin table

I noticed many plugins (such as Contact Form 7 and TablePress ) seemed to be using a standardized table design that looks like WP’s own default for managing posts, with Edit and Delete links on hover, a checkbox for each row, and bulk actions.

I dug around a bit and found the WP_List_Table class. It’s not an official developer API, but it’s stable and widely used for the creation of admin tables in plugins.

Reading about WP List Table led me to a few example codebases (this one is my favorite), a detailed guide, and even a generator.

(I recommend reading all of the aforementioned links before attempting to work with WP List Table, even if through a generator or boilerplate code.)

I used the generators to get started. (Definitely watch the video to see how all the parts fit together and how to name the files, using the generators alone is not enough to piece it together).

The generator did not include delete so I implemented that myself.

Implementing Delete (both single and bulk delete) in the WP List Table

I got stuck on implementing “Delete” (both the singular variety and the bulk kind) for a little while, mostly because I was trying to refresh the page myself after calling my delete method. Naively, I tried solutions like wp_redirect() right after calling my delete function, but that didn’t work – the page would reload but the stale, already-deleted row(s) were still in the table until the page was refreshed a second time or I would get a “headers already sent” error.

Ultimately, the solution was not to call any kind of redirect or refresh action but to simply call process_bulk_actions() before getting $items (in my code, that’s apb_get_all_product_boxes()) in the prepare_items() method in list-table.php.

The prepare_items() method (starting at about line 190) is called any time the list page is rendered, and the list page is automatically reloaded and rendered when clicking the Delete link or submitting the bulk action on the form. With that in mind, I didn’t need to reload the page manually – I just needed to make sure the deleted items were processed and removed from the db before retrieving the latest list of items.

For more on how I implemented Delete after using Tareq’s generated files as a starting point, see my comment on the generator’s repo here.

Here’s the merged pull request for this refactor.

And here’s how it all looks now:

Final thoughts on this refactor

It took a few days and it felt like backwards progress for a while, but I’m glad I did it – now my plugin looks more like “professional” plugins, both in-page and in the codebase, and I learned a lot in the process. I’d rather do it right than hold onto prototype-grade code.

Building it myself from scratch was still an important learning step for me. At this point, I feel like I might actually finish this thing because all that’s left is… implementing the image box! (And uninstalling, and finding and fixing bugs, and trying it out on a live site…)

Continue on to part 4!

Tutorial: Making a variety of 2D particle effects in Godot 3.1

In this tutorial: a step-by-step guide to making a few different particle effects in Godot 3.1. This guide assumes some familiarity with the Godot game engine.

I recently started adding particle effects to my hobby game project but I found that while the Godot docs offer a pretty good introduction to particles, I was still a bit lost when it came to some of the more advanced features like color ramps, stacking particle effects, and controlling them through code.

Note: the illustrative gifs I made for this guide run at 8 fps. They look a lot smoother in-engine and on target.

Godot 2d particle tutorial #1: floaty sparkles from a cauldron

I have a giant pink cauldron and I want it to “emit” pink sparkles that fade to white and disappear.

A sparkling pot of sparkles (the jump is just the gif looping, it runs smoothly in-game)

All of these begin as a scene (their own scenes, for the sake of organization) with a Particles2D node as the root.

The little yellow warning triangle tells us we need to assign a material to this particle effect, so in the Inspector scroll down to Process Material, roll out the bar and click where it says [empty].

Choose New ParticlesMaterial.

You should now have a steady stream of white dots in your viewport. These little white dots are just the placeholders for sprites you’ll attach to the effect later.

Click on ParticlesMaterials to roll out all the tweakable properties. (There are many and this guide covers some of them in more detail.)

Flipping gravity

First thing I did was reverse gravity from 98 (heavy!) to -30 (floaty!) so that the little particle dots emit upwards.

A negative Y value makes particles appear to travel up instead of down.

Changing the emission shape

Next, I changed the Emission Shape to a box and gave it a height and a width. This area represents the space in which new particles can spawn.

A short, wide rectangular box

Hey, it’s starting to look like bubbles floating up from a cauldron!

Adding a sprite texture

The next step is to add a sprite texture. I have an 8×8 simple “plus” graphic to serve as my sparkle for now.

Grab that sprite graphic and drag it over to the Textures > Texture field in Inspector tab like so:

Voila – the white dots are now white plusses.

Adding randomized rotation to each sparkle

Back in the ProcessMaterials section of the Inspector, open up the Angle property. If you just type a rotation value for Angle, all particles will emit at that angle. Increase Angle Random to 1 to generate every particle at a random angle.

Setting Angle to 45 and Angle Random to 1

Now we have randomized sparkle rotations.

(This gif is a lot choppier than how it looks in-engine.)

Adding a color ramp

I want my particles to start one color and fade to a different color as they reach the end of their lifespans. That’s easy to do with a Color Ramp. In the Color section, find Color Ramp and click on [empty]. Add a New Gradient Texture.

Click on the new GradientTexture to add a Gradient Map.

Click on that new Gradient to access the actual color gradient.

Here’s where things got unintuitive for me. The biggest hurdle was realizing the box to the right of the gradient is a button! I also didn’t notice the vertical adjustment boxes, since they start out at the extents of the gradient and are easy to overlook until you know they are there.

This gif attempts to demonstrate the color gradient UI.

How to use Godot’s gradient editor.
  • Slide the vertical boxes left/right to adjust how much of the gradient is dedicated to a particular color
  • Click on the vertical boxes to open a color picker (it’s easy to accidentally dismiss the color picker, as I do in this gif at least once)
  • Click anywhere in the gradient to add another color
  • (Right click on a box to remove it – not shown in gif)
  • With the color picker open, slide the “A” slider to adjust opacity.

Here’s what I went with for my pink-to-white cauldron sparkles:

Now you can see the sparkles starting out pink and turning white as they reach the end of their lifespan.

I saved this particle effect as its own scene, then place it (via drag and drop) into the scene where I want to use these particles.

From here, I continued to fine-tune their properties: I made their spawn box wider to better fit the width of the cauldron and I changed their gravity to -10 so they would float slower. I think there’s always going to be a bit of try-and-see-then-tweak-again when it comes to making particle effects, or at least that’s the case for me.

Godot 2d particle tutorial #2: ghostly glow on defeated heroes

From here on out I’m going to skip the setup steps covered in tutorial #1 and just show you some of the effects I was able to make and what parameters I used to achieve them.

Here, I wanted a ghostly “cloud” to surround defeated heroes.

I wanted the “ghost glow” to follow them around as they walk, so I made it a child of the hero node.

However, I control its appearance through script like so:

func ghost_mode(ghostMode):
if (ghostMode):
print("ghost mode on")
$body.modulate = Color(0.8, 0.7, 1)
$body.modulate = Color(1, 1, 1)

Parameters used to achieve this effect:

  • Amount: 9
  • Lifetime: 4
  • Preprocess: 3 (this makes it behave like it’s already been running for 3 seconds we don’t see the effect “start up” when we enter a scene where this effect is playing)
  • Emission shape: box (5x5x5)
  • Velocity: 10
  • Scale: 0.55 (because the puff png is too big otherwise)
  • Color ramp starts transparent and ends transparent, with purple in between
  • Material: CanvasItemMaterial
    • Blend mode: Add (so it makes things underneath the effect look bright and more ghostly-er)
    • Light mode: normal

Godot 2d particle tutorial #3: Boom! spawn-in animation

For this last one I wanted to achieve a “spawn in” effect for my game’s enemies. I wanted it to be big enough to cover the enemies popping in and I wanted to try layering at least two effects so that it looked like both clouds and sparkles happening at the same time.

Here’s what I ended up with after a bit of playing around:

Incoming! :D

This is two separate particles but they spawn at the same time.

Effect #1: purple puff clouds

They puff cloud is just a chunky Photoshop scribble with some randomization applied. Here’s the puff cloud by itself:

This is the .png used to make it. It’s just a fat brush stroke from Photoshop.


Parameters used to make this animation:

  • Amount: 6
  • Lifetime: 5
  • Preprocess: 0.25
  • Speed scale: 3.8
  • Explosiveness: 1
  • Spread: 180
  • Gravity: -4 on Y
  • Angle: 160
  • Angle random: 1
  • Scale: 0.55
  • Scale random: 0.03
  • Scale curve: Curve texture
Curve Texture is useful for fine-tune control over the scale of the particles through their lifespan. Here they start small, get bigger, then shrink again as they reach the end of their lifespan.
  • Color ramp is a gradient that starts and ends transparent with a solid section of purple in the middle

Effect #2: bright sparkle ring

This ring effect plays over the puff clouds.

Parameters used to make this animation:

  • Amount: 20
  • Lifetime: 1.6
  • Preprocess: 0.25
  • Speed scale: 1.5
  • Explosiveness: 1
  • Spread: 180
  • Initial velocity: 40
  • Angular velocity: 28
  • Linear accel: 1
  • Damping: 22
  • Angle: 45
  • Angle random: 1
  • Color ramp:

Spawning the two effects simultaneously

For the sake of completion, here’s the entire method that spawns my game’s mobs. I bolded the parts that spawn the particles. I add them as a child to the mobScene and show the mob sprites themselves after a brief pause so that the spawn-in animation starts slightly before the mobs are actually visible to the player.

func populate_mobs(mobs):
for i in mobs.size():
var mobScene = preload("res://baseEntity.tscn").instance()
var p_spawnCloud = load("res://particles/particles_spawnCloud.tscn").instance()
var p_boomRing = load("res://particles/particles_boomRing.tscn").instance()


mobScene.set_position(Vector2(mobPositions[str(i)]["x"], mobPositions[str(i)]["y"]))
mobScene.set_display_params(false, true) #no walking, show name

yield(get_tree().create_timer(0.5), "timeout")
get_tree().call_group("mobs", "show")
get_tree().call_group("mobs", "_draw_sprites")

Parting thoughts (and links to more readings)

OSU eCampus CS161 Intro to Computer Science review & recap

This post is part of an ongoing series recapping my experience in Oregon State University’s eCampus (online) post-baccalaureate Computer Science degree program. You can learn more about the program here.

With my successful completion of CS161, I am now 1/16th of the way to a Computer Science degree! Despite being labeled an “intro to CS” course, this class wasn’t a walk in the park – the two exams (worth 60% of the grade) were the tough part.

CS161 syllabus, topics

My CS161 was taught by Tim Alcon. He was remarkably responsive on the class forum (“Piazza”) and over email. There were something like 200+ students in the class, though, so assignment grading was done by a group of teacher assistants (TAs).

Syllabus: CS161 syllabus

Topics covered:

  • Introduction to C++ language
  • variables
  • methods
  • arrays
  • passing data into methods
  • data types
  • while loops, for loops
  • memory management (introduction)
  • pointers
  • object-oriented program structure
  • good coding style (comments, naming)

If you’re a prospective student reading this and these topics are all brand new to you, you should get familiar with them prior to the class. The class moves pretty quickly, especially past week 3.

These are all courses/video series I’ve worked through myself and recommend to anyone wanting to get started with programming:

CS161 class format

The course is 10 weeks long. Every Wednesday at midnight the next week’s homework and reading (called a “module”) becomes unlocked in the class portal (known as “Canvas”). You can do the reading/homework as fast or as slow as you want, as long as it’s turned in by the due date, typically the next Sunday or Wednesday (so you had either 5 or 7 days to get everything done before the next batch opened up). There weren’t any videos or supplementary materials beyond the book. Basically it’s read the chapter, do the homework, repeat. 

Early in the course, I found this drip-feed of content frustratingly slow. I wanted to work ahead and take advantage of free time when I had it. I usually had my assignments done within a day of their release. After about the halfway point, though, the class picked up the pace and I was turning in homework much closer to the Wednesday night deadline.

CS161 homework assignments

Every week had a reading assignment (usually 1-2 chapters from Starting out With C++: Early Objects) and a coding assignment. Some weeks also had a group assignment and/or a reflection assignment (1-2 pages written response). For the code assignments, you upload .cpp files to upload via “TEACH” (OSU’s interface for uploading homework).

The time commitment was reasonable, in my opinion. My daughter was born the same day class started so I had the advantage of being on maternity leave from work, but a newborn is demanding and I ended up squeezing homework and reading in anywhere I could, at odd hours of the day. In the early weeks of the class I spent about 4-5 hours a week on reading and homework combined. In the later weeks, I was spending 8-10 hours per week on the reading and homework combined. However, it’s worth adding that I’ve worked as a programmer (front end web developer) for the last 2 years, have already completed a web dev bootcamp, and have put myself through various online self-paced CS courses (this one just happens to be worth a college credit).

I thought the assignments were clear in their requirements and it was easy to understand what I needed to do.

The course materials suggest that you need a Windows machine and Visual Studio for CS161, but that’s not necessary – I did a lot of my homework on my Macbook and I never opened Visual Studio on my Windows machine. On my Windows computer, I used MinGW as my C++ compiler and wrote my code in Sublime Text. With this setup, I didn’t have to worry about Visual Studio adding anything extra to my files and my homework always compiled on Flip, the school’s Linux environment that you can log into and upload your project files to for testing. (This is the same environment the TA’s use to check if your work compiles.)

Some weeks had group assignments, which were coordinated over the Discussion groups in Canvas. The two major group assignments were basically “everyone upload last week’s homework, then decide amongst yourselves which one is best and write a page explaining why you picked it”. I found my classmates responsive and eager to complete the assignment; this wasn’t the group assignment horror-show you might remember from high school, at least not here in CS161 where it wasn’t about producing a completed project together.

Assignments were usually graded about a week or so after turning them in. Feedback was a line, at most, usually “Looks good!” or “You didn’t give this method the right name, -2 points”.


CS161 exams

The most important thing to understand about OSU CS eCampus exams is that they are “proctored”, which is academia-speak for “supervised”. This was my first experience with proctored exams. (And this will be the case of all exams for the online CS degree program, not just CS161.)

There are two proctoring options:

  • Take it in person at a local university/college/community college/test center (this is what I did)
  • Take it at your own computer with a live webcam stream of your face running the whole time with a service like ProctorU

I thought the ProctorU option was creepy as hell, plus I couldn’t guarantee the people I live with would actually be quiet while I took the exam. They require a 360 view of the room you’re in before you start, and any interruption is grounds for your test to be disqualified. Getting up to yell at someone / deal with a fire / etc is enough to make the person supervising you over ProctorU disqualify your test. Reading others’ first-hand experiences with ProctorU also put me off the service pretty quickly, but I never actually tried it myself.

Taking the exams at my local community college’s test center was easy once I confirmed with them that they were approved for OSU tests. I scheduled a time (they even had Saturday hours), showed up, sat down at a computer, logged into my OSU Canvas account, and started the test. The test is timed, and the test center provides paper and pencil (which they keep after the exam). The test runs in your web browser. My local test center charged $35 per test.

As for the exams themselves, I found them rather tricky. Each of the exams (there are 2) are 20 multiple choice questions with 4-5 answers to pick from. You have to hand-trace through the code (which is often iterative) and spot any errors that might be included in the code. (The paper and pencil help a lot here.)

In real life, you get the help of a compiler and unit tests (that I’m sure you wrote because you’re a good programmer) to help you understand (or debug) a bit of code, so the tests felt unnecessarily difficult and unlike my professional coding experience.

Here’s an example. One exam question had something like this (embedded in a much larger block of code):

if (x = 3) {
   ...stuff here...

I caught the single = sign, but I didn’t know it would actually do something in this case. In C++ (and other languages), this evaluates to true and sets x to 3. I’m just citing this as an example of how you have to know the fiddly bits of C++ to really excel at the exams. (I managed an 80% and an 85% on the exams.)

The test is graded as soon as you submit it, but you won’t know which ones you got wrong until they unlock the tests a few weeks after they’re done. Furthermore, while they’ll eventually tell you which questions you got wrong, they won’t tell you what the correct answer was.


So, don’t expect the exams to be much of a learning experience until the course has ended and you can work through the questions with an IDE and compiler.

Overall impression: OSU CS161

OSU’s eCampus Computer Science program looks solid from here, and I thought CS161 was a good value. The materials were well put together, the pacing was reasonably challenging, and the course’s time demands seem manageable for someone with a full-time job and family (I was on maternity leave while I took the course). I came into the class with more prior experience than the class is really meant for, but I still felt satisfied and challenged by the material. The OSU eCampus Reddit forum is a helpful resource for information on individual classes, admission process, instructor reviews, etc.

Onwards to CS162!

Code Fellows Post-Accelerator Update (4 months into first job)

It’s been…

  • Several years since I first dreamed of writing script or code for a living
  • 1 year since I left my unhappy video game designer job
  • 6 months since I graduated from the Code Fellows Full Stack JavaScript Dev Accelerator
  • 4 months since I started my full-time programmer job

What a trip! Thanks to Code Fellows in Seattle, I am super happy to report that I am now a full-time programmer and loving my new job!


I had tinkered with coding for years in my free time, but never in a substantial enough capacity to turn it into a full time job on my own. Code Fellows was that missing piece, and this is my post-Accelerator update!

My review of the Seattle-based Dev Accelerator can be found here, if you’re curious about the 8 week program itself.

Yes, I got a job after Code Fellows!

@CodeFellowsOrg is now in Chicago and Portland!

And it’s a great job! Like, an unbelievably great job where they pay me to solve interesting Angular and JavaScript problems! My title is Associate Software Development Engineer and I work at Expedia in Bellevue, WA.

So, yes, to all those wondering (and emailing me!), Code Fellows will work you hard, but it is sufficient training for an entry-level programming job (provided you do your part), and the skills you learn in the class will be useful in your job, even if your job is in a different language or technology stack.

Job search rocket fuel: The mid-accelerator resume blast

Code Fellows definitely made good on their promise to put student resumes in front of local employers. Halfway through the Accelerator (4 weeks in), Code Fellows collected and reviewed resumes from every student and fired them off to 40+ Seattle and Eastside employers. Holy wow – they knew about companies I’d have never found on my own.

The “blanket the city” approach worked, but I had a few small gripes that I think other students should be aware of.

  1. The resume blast went to companies I wasn’t interested in (…yet). I gave preference to companies closer to me on the Eastside (so I wouldn’t have to relocate), but my resume went to plenty of companies in downtown Seattle. I felt bad turning down these companies (burning bridges! ahh!), especially since I knew I would become more interested in relocation if my job search started to drag on.
  2. I prefer to customize my resume and cover letter to each position, emphasizing different aspects of my experiences for different positions.
  3. The blast went out too early. My final Accelerator project, my post-Accelerator project, and my portfolio website were not on that early version of my resume. Employers I talked to over the next couple months didn’t know about these things, and those projects and my portfolio site were the strongest showcases of my work.

Basically, I didn’t have iron-clad control over my job search in the first few weeks. And I like iron-clad control over my job searches.

I had only a vague sense of which companies I had already “applied” to and I inadvertently wasted the time of employers I probably wouldn’t have applied to on my own (because they were too far away or didn’t have the kind of workplace culture or benefits I was looking for).

But if that’s my biggest gripe, then I don’t have much to complain about. Code Fellows did a good job supporting its grads, and a quick glance at my fellow classmates’ LinkedIn profiles suggests more than half have already found full time gigs.

Really, I didn’t have to look hard for interesting job opportunities after graduating, and I still don’t – Code Fellows continues to send job leads to alumni, and my LinkedIn profile gets so much email I’m kind of afraid to look in that inbox.

The First Calls

The first couple weeks after my September 26th graduation were really quiet (which was good, the Accelerator was intense and having a little time “off” was beneficial) and then I started getting calls and emails from employers in late October and early November.

Most of these came from “resume blast” employers, but I also ended up in the hands of some recruiters trying to fill really short project positions (like, 3-week or 2-month contract projects). I thought these projects sounded exciting but all of these opportunities fell through for some reason or another.

A big question near the end of the Accelerator that many students asked was whether recruiters were worthwhile. I’ve personally never had a productive relationship with a recruiter in nearly ten years in tech, but someone must be getting value out of recruiters since they’re still in business.

For whatever it’s worth, the three companies I ultimately interviewed with contacted me directly, either via their technical director or their own hiring department, with no recruitment firm involved.

Technical Interviews

By mid-November I had phone interviews scheduled with three companies. Two of them had my info from Code Fellows, and one of them I had applied to on my own. Of those three companies I interviewed with, two chose to conduct the technical interview over the phone.

The first company had a setup where I shared a screen with my interviewer and coded in real-time as my interviewer watched and talked to me over the phone.

The second company conducted the technical interview as a series of questions, sans-computer, although my interviewer had poked through my Github repos and had some questions for me about code I had posted to Github.

The third company (where I now work!) brought me in for a one-hour in-person technical interview, which I really enjoyed and preferred over the phone interviews. This technical interview had the most in common with Code Fellows’s style of interview training, where the interviewer asked me questions and I wrote code on the whiteboard and answered questions as we went along.

In all three technical interviews with three different companies, I felt that my Code Fellows training and in-class interview practice had sufficiently prepared me for the questions I was asked. I was asked questions I didn’t know the answer to in all three interviews, but it wasn’t the end of the world. I just said I didn’t know, said what I would do to find out, then said that I would love to know, and in all cases, my interviewer explained whatever it was to me. (Yay, I learned something new!)

Technical Interviews: Questions I was asked

In no particular order, here are the kinds of questions I remember being asked:

  • Write a function that determines if a string is a palindrome
  • What does REST mean? Why is it important?
  • Write a function that returns just the odd numbers from an array I pass into it
  • Now modify that function to return every other odd number
  • Describe dependency injection in Angular
  • Tell me what kinds of tests you would write for that (whatever that was)

Keeping up after the Accelerator

I filled my post-Accelerator free time building a brand new AngularJS app of my own, a sort of “capstone project” that summarized my knowledge thus far. This project kept my skills fresh and I would recommend other Code Fellows grads do the same (after graduation, of course) to really solidify their understanding of the concepts likely to come up in interviews.

My post grad project: a recipe site with a back-end interface for adding and editing recipes. I rolled my own CSS and it even has automated tests!

I brought this project with me to my interview on a laptop so I could show it to my interviewer, and that seemed to go over very well. (I got the job, after all!)

Other things I did to stay sharp after the Accelerator:

  • Codewars “kata” – some of these were really hard but they’re also one of the only training things I’ve found that includes testing
  • Updated my WordPress blogs’ themes and added customization I always wanted but never really understood how to do before (this stuff was easy after the Accelerator)
  • Built my coding resume / portfolio site from scratch
  • Aimed for a minimum of 1 meaningful Github push per day on whatever project of my choosing (I find streaks and those little green cubes very motivational)
  • Read up on concepts I learned about in the Accelerator but wanted to understand better, like Big O, asynchronous Javascript, data structures

My first month on the job

Like many grads, my primary fear going into my first programming job was that I wasn’t sufficiently qualified. I still felt pretty green, despite all my experience. (Some people tell me this feeling of being inept despite accomplishments that prove otherwise may never fully go away, and recognizing that definitely helped.)

My first week on the job was spent learning the code base, the project structure, learning the workflow (how to run tests, how to get a build running), and setting up my work laptop.

There was so much to learn, and this project is so much more complex than anything I’d coded in before. (This is why I think building real, standalone apps / programs is best for learning to code once you’re past the online tutorial basics.)

My work project is more complex than anything I ever built on my own.

Fortunately, everyone was happy to help and answer questions, and I quickly found several more Code Fellows alumni at the company who started before me or on the same day as me. We met up at a local Starbucks early on to share experiences, which was reassuring for everyone involved.

In that first month, my main contribution was adding a button that exposed a back-end feature the rest of the team had been working on for some time. I wrote the logic that determined when that button would be clickable, and added unit and end to end tests to help spot any future regressions.

I also had the opportunity to debug existing Ruby/Cucumber tests, learn a little bit of Scala, and write a few MySQL queries to look at how data was saved in the database. In that first month, I found that the biggest challenge wasn’t writing new code, it was understanding existing code and the complexities of the project’s structure.

The next 3 months

Around weeks 5-6 I started to feel like a more full-fledged, contributing member of the team. The vast majority of my work is in modifying existing code to perform a new function or to fix an unwanted behavior.

Here are just a few of the things I worked on in that time:

  • Small optimizations to Cucumber test suite aimed at reducing the test code’s reliance on fragile XPaths and removing sleep() and wait() calls
  • Improvements to the way dates are handled in the app, including adding the much-beloved moment.js library to the project
  • Collaborating with another programmer to develop a date range “collision” algorithm that can check if a variety of date ranges overlap correctly (or incorrectly) according to a complex set of business rules
  • Upgrade project’s Angular version and assist in the migration
  • I had the opportunity to attend a day-long Test Driven Development workshop and bring those practices back to my daily work

My team’s leaders are big fans of pair programming (to the extent that we have dedicated 1pm-4pm “core pairing hours” every day), so a lot of the work I do is in the company of at least one other engineer. I’ve learned so many good techniques and habits from working with my teammates, and I can’t overstate how great this has been for my own development and quick integration with the team.

(I hope it’s apparent from my writing here how very happy I am to be working on this project with this team – I love it, it’s better than I ever dared to hope.)

Happy Ending / New Beginning

So that’s it! I can’t believe it’s been six months already. The Code Fellows Accelerator changed my life: my new role is challenging, and working at Expedia with my team has kept me just as inspired and excited as I was when I embarked on this journey a year ago.