Adam's Blog
×

Creative Pact 2023

Friday January 06, 2023
Category: creativepact2023

This year I will be doing another Creative Pact where I will be learning gen~ by making something every day for the month of June 2023. It looks like Creative Pact is largely a thing of the past, and I am not doing this in January to participate in Genuary, but hoepfully there will be something interesting for other folks too.

There is a great deal of documentation and tutorials available across the internet and I will do my typical scattered approach to learning and exploring, but trying to stay grounded in Graham Wakefield & Gregory Taylor’s book Generating Sound and Organizing Time. I have been reading it and it has removed the block I had with using gen at all.

I expect to also dive into oopsy and try to get some of the more fun patches onto a bluemchen and do some noise making in the modular world.

myo.js Explorations

Sunday November 20, 2016
Category: Uncategorized

In the past I have endeavored to work with things that I like. Right now my two favourites are flocking.js, MYO. In particular, I have been very happy to get back into node.js and taking a look at the myo.js bindings.
The basic demos work well but I have two myos, so it would be great to address each separately. The API provides a Myo object that keeps an array of all of the myos connected at the time. Most of the demo code uses the Myo.on('connect, function(){}; to check the array and then keep track of the left and right arm (which is how I want to use them and how I expect most people to use them too).
The problem is that when you check the myo objects once they have connected a lot of their parameters are not set:

[ { macAddress: 'f3-c6-21-d0-98-b3',
name: 'Adam Tindale's Myo',
connectIndex: 0,
locked: true,
connected: true,
synced: false,
batteryLevel: 0,
lastIMU: undefined,
arm: undefined,
direction: undefined,
warmupState: undefined,
orientationOffset: { x: 0, y: 0, z: 0, w: 1 },
events: [],
connectVersion: '1.5.1970.2' } ]

In order to get these parameters I waited for the unlock event and then checked the calling object for its arm parameter. I have two references for specific myos leftMyo and rightMyo that I check to see if they are undefined. If they aren’t then I check the calling object using this in order find its arm parameter. I assign the object to my references and then inititialize the listeners at that point. If you do it before you define the objects then javascript rightly complains that you are trying to put listeners on undefined objects (because they obviously aren’t yet defined).
Here is an example I whipped up of a basic two handed myo.js that sends OSC messages using osc.js.

var Myo = require('myo'), 
    leftMyo, rightMyo;


var BarCli = require('barcli'); 


var barcli_lx  = new BarCli({label: "left x", range: [-1, 1]});
var barcli_ly  = new BarCli({label: "left y", range: [-1, 1]});
var barcli_lz  = new BarCli({label: "left z", range: [-1, 1]});
var barcli_rx  = new BarCli({label: "right x", range: [-1, 1]});
var barcli_ry  = new BarCli({label: "right y", range: [-1, 1]});
var barcli_rz  = new BarCli({label: "right z", range: [-1, 1]});

var barcli_lxa  = new BarCli({label: "left x accel", range: [-1, 1]});
var barcli_lya  = new BarCli({label: "left y accel", range: [-1, 1]});
var barcli_lza  = new BarCli({label: "left z accel", range: [-1, 1]});
var barcli_rxa  = new BarCli({label: "right x accel", range: [-1, 1]});
var barcli_rya  = new BarCli({label: "right y accel", range: [-1, 1]});
var barcli_rza  = new BarCli({label: "right z accel", range: [-1, 1]});


// SETUP MYO
Myo.on("unlocked", function(){
    // this seems to work best here
    Myo.setLockingPolicy('none');

    if (typeof leftMyo !== "undefined" && typeof rightMyo !== "undefined")
        return;
    if (typeof leftMyo === "undefined" && this.arm === "left"){
        leftMyo = this; 
        leftMyo.on('pose', function(pose){
            console.log(this.arm+ ":" + pose);
        });
        leftMyo.on('pose_off', function(pose){
            console.log(this.arm+ ":" + pose);
        });
        leftMyo.on('locked', function(){
            console.log(this.arm + ": locked"); 
        });
    }
    if (typeof rightMyo === "undefined" && this.arm === "right"){
        rightMyo = this; 
        rightMyo.on('pose', function(pose){
            console.log(this.arm+ ":" + pose);
        });
        rightMyo.on('pose_off', function(pose){
            console.log(this.arm+ ":" + pose + " off");
        });
        rightMyo.on('unlocked', function(){
            console.log(this.arm + ": unlocked"); 
        });
    }
});

Myo.on("connected", function(){
    console.log(this);
});

Myo.connect('org.adamtindale.myoosc', require('ws'));

View this code on GitHub

Day 7

Saturday May 07, 2016
Category: Creative Pact 2016

Screenshot of software.

A simple test with the MYO and C4ios.

//
//  WorkSpace.swift
//  DAY7
//
//  Created by Adam Tindale on 2016-05-07.
//  Copyright © 2016 Adam Tindale. All rights reserved.
//

import UIKit

class WorkSpace: CanvasController {
    
    var start = TextShape(text: "Look for Myos")
    
    override func setup() {
        let notifer = NSNotificationCenter.defaultCenter()
        notifer.addObserver(self, selector: "didConnectDevice:", name: TLMHubDidConnectDeviceNotification, object: nil)
        notifer.addObserver(self, selector: "didChangePose:", name: TLMMyoDidReceivePoseChangedNotification, object: nil)

        start!.addTapGestureRecognizer { location, point, state in
            let controller = TLMSettingsViewController.settingsInNavigationController()
            self.presentViewController(controller, animated: true, completion: nil)
        }
        start!.frame = Rect(0,0,canvas.width/2, canvas.height/2)
        start!.adjustToFitPath()
        start!.center = canvas.center
        canvas.add(start)
    }
    
    func didConnectDevice(notification: NSNotification) {
        start!.text = "Hello Myo"
        start!.center = canvas.center
    }


    func didChangePose(notification: NSNotification) {
        let eventData = notification.userInfo as! Dictionary<NSString, TLMPose>
        let currentPose = eventData[kTLMKeyPose]!
        
        print(currentPose)
        
        switch (currentPose.type) {
        case .Fist:
            start!.text = "Fist"
        case .WaveIn:
            start!.text = "Wave In"
        case .WaveOut:
            start!.text = "Wave Out"
        case .FingersSpread:
            start!.text = "Fingers Spread"
        case .DoubleTap:
           start!.text = "Double Tap"
        default: // .Rest or .Unknown
            start!.text = "Hello Myo"

        }
        start!.center = canvas.center
    }



}

View this code on GitHub

Day 6

Friday May 06, 2016
Category: Creative Pact 2016

Another simple test today. A button. Are buttons in iOS really this bad? Is there no UIControlAction that deals with touch releases being both inside and outside of a button? Odd.

Screenshot of software.

//
//  WorkSpace.swift
//  DAY6
//
//  Created by Adam Tindale on 2016-05-06.
//  Copyright © 2016 Adam Tindale. All rights reserved.
//

import UIKit

class WorkSpace: CanvasController {

    let trigger = UIButton(type:UIButtonType.System)
    var flocking = UIWebView()

    override func setup() {
        // loads flocking.js in home.html
        flocking.mediaPlaybackRequiresUserAction = false
        let url = NSBundle.mainBundle().URLForResource("home", withExtension: "html")
        let request = NSURLRequest(URL: url!)
        flocking.loadRequest(request)
        
        trigger.frame = CGRectMake(0, 0, 100, 30)
        trigger.center = CGPoint(canvas.center)
        trigger.setTitle("Press Me", forState: .Normal)
        canvas.add(trigger)
        
        trigger.addTarget(self, action: "triggerFlock", forControlEvents: .TouchDown)
        trigger.addTarget(self, action: "triggerFlockOff", forControlEvents: .TouchUpInside)
    }

    func triggerFlock(){
        self.flocking.stringByEvaluatingJavaScriptFromString("synth.set('thing.mul.gate', 1);")
    }
    
    func triggerFlockOff(){
        self.flocking.stringByEvaluatingJavaScriptFromString("synth.set('thing.mul.gate', 0);")
    }

}

View this code on GitHub

<html>
    <head>
        <style>
            *{border:0;margin:0;}
            #wave{position:fixed;top:0;left:0;width:100%;height:100%;background-color:blue;}
            </style>
    </head>
    <body>        
        <script src="flocking-all.min.js"></script>
        <script>
            var synth = flock.synth({
                synthDef:
                    {
                        id: "thing",
                        ugen: "flock.ugen.whiteNoise",
                        mul: {
                            ugen: "flock.ugen.env.simpleASR",
                            start: 0.0,
                            attack: 0.01,
                            sustain: 0.2,
                            release: 0.1,
                            gate: 0.0
                        }
                    }
                });
                synth.play();
            </script>
    </body>
</html>

View this code on GitHub

Day 5

Thursday May 05, 2016
Category: Creative Pact 2016

Today was a tooling day. I’ve been building the apps in the simulator but what about launching it on actual hardware. So, because I am running 9.3 on my phone I had to finally upgrade to 10.11. Then it was updating XCode to the latest version and reinstalling C4. Fun times. The result was great to be able to walk around with the results on my phone. Hoorah!

To make things more fun I checked out Dringend, an app that connects to your mac and lets you code on your device and then launch the result on your device. No more plugging in the phone just to upload. Even better I can do a bit of hacking on the go. Awesome. Just awesome. I had a bit of a problem getting started and emailed the developer who had me up and running in less than an hour. Amazing.

Day 4

Wednesday May 04, 2016
Category: Creative Pact 2016

A simple one today, but importantly a variant of the flocking sketch. This is a stereo envelope that can be modulated with a single slider. Enjoy.

//
//  WorkSpace.swift
//  DAY4
//
//  Created by Adam Tindale on 2016-05-04.
//  Copyright © 2016 Adam Tindale. All rights reserved.
//

import UIKit

class WorkSpace: CanvasController {
    var webview = UIWebView()
    
    let freqslider = UISlider()
    
    override func setup() {
        // loads flocking.js in home.html
        webview.frame = CGRectMake(0, CGFloat(canvas.height/4.0), CGFloat(canvas.width), CGFloat(3.0*canvas.height/4.0))
        webview.mediaPlaybackRequiresUserAction = false
        let url = NSBundle.mainBundle().URLForResource("home", withExtension: "html")
        let request = NSURLRequest(URL: url!)
        webview.loadRequest(request)
        
        
        freqslider.frame = CGRectMake(10, CGFloat(canvas.height/2 - 15), CGFloat(canvas.width - 20), 30)
        freqslider.value = 0.1
        canvas.add(freqslider)
        
        freqslider.addTarget(self, action: "freq:", forControlEvents: UIControlEvents.ValueChanged)
    
    }
    func freq(sender: UISlider!){
        let myval = sender.value * 20.0
        self.webview.stringByEvaluatingJavaScriptFromString("synth.set('lefthat.mul.gate.freq', \(myval) );synth.set('righthat.mul.gate.freq', \(myval) );")
    }

}

View this code on GitHub

<html>
    <head>
        <style>
            *{border:0;margin:0;}
            #wave{position:fixed;top:0;left:0;width:100%;height:100%;background-color:blue;}
            </style>
    </head>
    <body>        
        <script src="flocking-all.min.js"></script>
        <script>
            // Sine tone shaped by a simple attack/sustain/release envelope and periodically triggered.
            var synth = flock.synth({
                synthDef: [
                    {
                        id: "righthat",
                        ugen: "flock.ugen.whiteNoise",
                        mul: {
                            ugen: "flock.ugen.env.simpleASR",
                            start: 0.0,
                            attack: 0.01,
                            sustain: 0.2,
                            release: 0.1,
                            gate: {
                                ugen: "flock.ugen.impulse",
                                rate: "control",
                                freq: 2,
                                phase: 0.5
                                }
                             }
                        },
                        {
                            id: "lefthat",
                            ugen: "flock.ugen.whiteNoise",
                            mul: {
                                ugen: "flock.ugen.env.simpleASR",
                                start: 0.0,
                                attack: 0.01,
                                sustain: 0.2,
                                release: 0.1,
                                gate: {
                                    ugen: "flock.ugen.impulse",
                                    rate: "control",
                                    freq: 2,
                                    phase: 0.0
                                }
                            }
                        }
                    ]
                });
                synth.play();
            </script>
    </body>
</html>

View this code on GitHub

Day 3

Tuesday May 03, 2016
Category: Creative Pact 2016

Today I made a simple sketch using UIWebView.stringByEvaluatingJavaScriptFromString(string:string) to send UISlider values from C4 to Flocking. It worked! There is simple synth that has a frequency and amplitude control and I used the flock.ugen.scope in order to display the output in the UIWebView. A few simple tricks together makes for a great demo.

Next trick will be to start to make something that sounds interesting. I’m starting to get confident enough to attempt it.

Screenshot of software.
Screenshot of software.

//
//  WorkSpace.swift
//  DAY3
//
//  Created by Adam Tindale on 2016-05-03.
//  Copyright © 2016 Adam Tindale. All rights reserved.
//

import UIKit

class WorkSpace: CanvasController {
    var webview = UIWebView()

    let freqslider = UISlider()
    let ampslider = UISlider()
    
    override func setup() {
        
        // loads flocking.js in home.html
        webview.frame = CGRectMake(0, CGFloat(canvas.height/4.0), CGFloat(canvas.width), CGFloat(3.0*canvas.height/4.0))
        webview.mediaPlaybackRequiresUserAction = false
        let url = NSBundle.mainBundle().URLForResource("home", withExtension: "html")
        let request = NSURLRequest(URL: url!)
        webview.loadRequest(request)
        canvas.add(webview)
        

        freqslider.frame = CGRectMake(10, 50, CGFloat(canvas.width - 20), 30)
        ampslider.frame = CGRectMake(10, 100, CGFloat(canvas.width - 20), 30)

        freqslider.value = 0.4
        ampslider.value = 0.25
        
        canvas.add(freqslider)
        canvas.add(ampslider)
        
        freqslider.addTarget(self, action: "freq:", forControlEvents: UIControlEvents.ValueChanged)
        ampslider.addTarget(self, action: "amp:", forControlEvents: UIControlEvents.ValueChanged)
    }
    
    func freq(sender: UISlider!){
        let myval = sender.value * 1000.0
        self.webview.stringByEvaluatingJavaScriptFromString("synth.set('singer.freq', \(myval) );")
    }

    func amp(sender: UISlider!){
        let myval = sender.value
        self.webview.stringByEvaluatingJavaScriptFromString("synth.set('singer.mul', \(myval) );")
    }
    
}

View this code on GitHub

<html>
    <head>
        <style>
            *{border:0;margin:0;}
            #wave{position:fixed;top:0;left:0;width:100%;height:100%;background-color:blue;}
        </style>
    </head>
    <body>
        <canvas id="wave"></canvas>
        
        <script src="flocking-all.min.js"></script>
        <script>
            var synth = flock.synth({
                synthDef: {
                    ugen: "flock.ugen.scope",
                    source:{
                        id: "singer",
                        ugen:"flock.ugen.sinOsc",
                        freq: 440,
                        mul: 0.25
                    },
                    options:{
                        canvas: "#wave",
                        styles: {
                            strokeColor: "#777777",
                            strokeWidth: 2
                        }
                    }
                }
            });
            synth.play();
            </script>
    </body>
</html>

View this code on GitHub

Day 2

Monday May 02, 2016
Category: Creative Pact 2016

Code. Fail. Stop. Sleep. Repeat.

Sometimes this works. But only if you insert share somewhere in the loop. Yesterday’s sketch was great to get my coding chops resurected but didn’t yield that much useful code for the world. After posting to the flocking mailing list, Colin reminded me of the recent iOS bug and promptly fixed it. Amazing.

So, I took yesterday’s code and stripped back a few parts and made a simple on and off button with some C4 animations. I love the way C4 morphs between shapes. I made a simple block of text be the start and morph to a stop button. The flocking sketch is still simple, but it is a start to something wonderful. I’m going to stop with this small victory.

Screenshot of software.
Screenshot of software.
Screenshot of software.
Screenshot of software.

//
//  WorkSpace.swift
//  DAY2
//
//  Created by Adam Tindale on 2016-05-02.
//  Copyright © 2016 Adam Tindale. All rights reserved.
//

import UIKit

class WorkSpace: CanvasController {
    
    var webview = UIWebView()
    var myshape = TextShape()
    var started = false

    override func setup() {
        // loads flocking.js in home.html
        webview.mediaPlaybackRequiresUserAction = false
        let url = NSBundle.mainBundle().URLForResource("home", withExtension: "html")
        let request = NSURLRequest(URL: url!)
        webview.loadRequest(request)

        myshape.text = "Touch to Play"
        myshape.adjustToFitPath()
        myshape.center = canvas.center
        canvas.add(myshape)
        
        let playanimation = ViewAnimation(duration: 1.0){
            self.myshape.path = Rectangle(frame: Rect(0,0,100,100)).path
            self.myshape.adjustToFitPath()
            self.myshape.center = self.canvas.center
        }
        let resetanimation = ViewAnimation(duration: 1.0){
            self.myshape.path = Circle(center: self.canvas.center, radius: 50).path
            self.myshape.adjustToFitPath()
            self.myshape.center = self.canvas.center
        }
        
        myshape.addTapGestureRecognizer { locations, center, state in
            if (self.started  == false) {
                self.webview.stringByEvaluatingJavaScriptFromString("synth.play();")
                playanimation.animate()
            }else{
                self.webview.stringByEvaluatingJavaScriptFromString("synth.pause();")
                resetanimation.animate()
            }
            self.started = !self.started
        }
    }
}

View this code on GitHub

<html>
    <body>
        
        <script src="flocking-all.min.js"></script>
        <script>
            var synth = flock.synth({
                    synthDef: {
                    ugen: "flock.ugen.sinOsc",
                    freq: 440,
                    mul: 0.25
                }
            });
                                                                                        
            </script>
    </body>
</html>

View this code on GitHub

Day 1

Sunday May 01, 2016
Category: Creative Pact 2016

I’m doing another Creative Pact! This May I will create a new thing every day and put up on this blog. I am going to work with 3 things that I like: flocking.js, MYO, and C4. Hopefully by the end of the month I will be able to combine all of them masterfully.

My first work for creative pact 2016 is a failure, in the sense that it doesn’t yet work. I tried to create a C4 app with a UIWebView inside of it that loads flocking. I started by following a tutorial to get UIWebview to load a webpage and then added jquery. OK. So far so good.

The next step was to load flocking. I added this to the HTML page and I got some messages on the console (frameSizeChanged = 4096). Great. Then I remembered that Apple prevents audio from being loaded in webpages without some sort of user action. So, I looked through the web again and found the trick. Hooray, I thought. No sound. I tried doing a body click with jQuery to trigger the flock.play() but that didn’t work. So, I tried loading a sound file, which also didn’t work. Can flocking play in a UIWebView? Maybe, but not by me today. Tomorrow is another day.

//
//  WorkSpace.swift
//  UIWebViewFlock
//
//  Created by Adam Tindale on 2016-05-01.
//  Copyright © 2016 Adam Tindale. All rights reserved.
//

import UIKit

class WorkSpace: CanvasController {
    
    var webview = UIWebView()

    override func setup() {
        webview.frame = CGRectMake(0, 0, 200, 200)
        webview.mediaPlaybackRequiresUserAction = false
        let url = NSBundle.mainBundle().URLForResource("home", withExtension: "html")
        let request = NSURLRequest(URL: url!)
        webview.loadRequest(request)
        canvas.add(webview)
        
        // doesn't work
        //webview.stringByEvaluatingJavaScriptFromString("alert('ffff')")
        
        // doesn't work
        /*
        let xx:String?
        xx = webview.stringByEvaluatingJavaScriptFromString("$('#ttt').html('something else')")
        print(xx!)
        */
        
        canvas.addTapGestureRecognizer { locations, center, state in
            //self.webview.stringByEvaluatingJavaScriptFromString("alert('ffff')") // works
            self.webview.stringByEvaluatingJavaScriptFromString("$('#ttt').html('something else')")
            // doesn't work
            //self.webview.stringByEvaluatingJavaScriptFromString("document.getElementById('some_sound').play();")
            //self.webview.stringByEvaluatingJavaScriptFromString("synth.play();")
            
        }
    }
}

View this code on GitHub

<html>
<body>
    HELLFOOALJKJLJDF
    <div id="ttt"></div>
    
    <script src="jquery.min.js"></script>
    <script src="flocking-no-jquery.min.js"></script>
    <script>
        $('#ttt').html("jfjfkjlkjf");//test
        
        var synth = flock.synth({
            synthDef: {
                ugen: "flock.ugen.sinOsc",
                freq: 440,
                mul: 0.25
            }
        });
                                
        synth.play();
        
        $("#ttt").click(function(){
            synth.play();
            flock.enviro.shared.play();
        });
        
    </script>
    
    <audio id="some_sound" controls>
        <source src="Loop.aif" type="audio/aif">
    </audio>
    <script>
        document.getElementById('some_sound').play();
    </script>
</body>
</html>

View this code on GitHub

Tour de Terra Cotta 2015

Monday August 03, 2015
Category: Uncategorized

This week has been a bit funny on the bike. Flats, flats, and more flats. I woke up this morning and got ready but when I went to load my bike the rear tire was deflated. I pumped up the tire and heard the dreaded hiss. I changed the tire and the tube and got it installed. We piled into the car to head out a bit late. About half way to the race I realized that I had forgotten my water bottle on the counter. I had a gel, but no water, so I drank a bit of water in the car and prepared to be a little dry. I figured it was a shorter race, so I should be ok. Katherine suggested I just look around to buy a water bottle. I was going to get there just in time to register and make a quick trip around.

We got to the grounds and I found a Skratch Labs tent. I explained my sob story and they gave me a bottle with the mix I had planned to be drinking. I joked that if I won I’d let them know... I knew that I wanted to win but bike races are prickly things. I got out to find the start and hopefully get a few minutes of warmup in the legs. Luckily I had gotten the start time wrong, I had an extra half hour. Phew! I found a little stretch and started removing the bricks from my legs. I was not feeling good at first but it started to clear up. I figured it was not my day, so I may as well just enjoy it. I detected some rubbing of the wheel and got the wheel re-aligned. Things might be ok.

I got to the start line and took stock. I lined up close to the front and took a comment from someone who thought it was a queue and that I should be at the back of the line. Team Kurzawinski was out in force. I found one Morning Glory and made eye contact. I was glad to have a potential friend around.

The race was off and up the first hill I was not positioned too well but as we went up I wasn’t pushing overly hard and yet I was moving up - Morning Glory workouts paying off. Kurzawinski had two front groups pulling on either side of the road. They weren’t moving too quickly and were not very well organized. This was great for me, but I knew that there would be some plan coming up. I’d seen some videos of previous races and the last time up the hill there had been a small breakaway, so I assumed that was the grand tactic. I planned to be in that final break and go from there.

A single rider broke from the pack at the third cornr. Kurzawinski did not chase. I was a bit nervous to see the race move away from me already but figured we had time. At the second hill we caught him and I gave him a "Great Break" as we went past. He gave me a tired reply and were up the hill. The field was getting smaller and I was trying to stay as close to the front as I could. I had moved from 20th to about 6th and was trying to stay there. Morning Glory friend was there, so I shared my plan and told him we should go together. He agreed.

We got around to Old School Road and then the leader started zig zagging across the road. The first time we were nearly moved into the gutter and it happended a few more times. I detected the problem and became angry. I yelled "Taking Your Fucking Turn Pulling Through, and Keep Your Line Straight!" I moved to the front and looked at the offenders in the face and said very loudly "ENOUGH"

I started my pull. I did my turn, flicked my elbow. Nothing. "Pull Through!" from me. Morning Glory friend was there. We had some nice words about keeping it fast and safe. Things were looking up. We came to the downhill an had a laugh at people racing to a downhill, the race is on the uphill!

`

At the bottom the Kurzawinski team made a duo move. I was too far back and was not happy again. Luckily the move lasted about 500 meters. Great. The hill. I gunned it. There was an independent in the lead and I was on his wheel. As we crested the hill he started to recover, I yelled "Don’t slow down" and pulled through. I looked back and he was gone and the peleton was a good deal behind. I was feeling good and confident. My speed was good, keep it up. My family was cheering half way through this straight and I could feel the excitement from them as I went past solo in the lead.

I got around the next corner and into the headwind. I knew I was going to slow down and hoped that the peleton was going to continue not working well together. They didn’t. Even better, my Morning Glory friend later told me that he moved to the front of the group and sat up to give me some more space. I needed it. I was starting to doubt. I started to think about all of the people who had gotten me this far: Morning Glory, riding friends, family, friends. I had to keep it up. Once I wasn’t caught along this stretch I figured that if I got to the top of the last hill and pedalled down it then I should have all but won. It was true. I got around the last corner, continued to pedal with what I had left and at 500 meters I could sit up and enjoy the moment.

My Morning Glory friend, NAME HERE, finished first in his age category depite helping me. It was a good day. My family arrived in time for the podium ceremony and I even lucked out and won a door prize of a Pedro’s Chain Pig.

Overall, I really enjoyed the event. I caught up with the swerver and it turned out to be his first group ride. I wondered if the event might provide the beginners with a set of links to videos and writings about how to organize in a group. It is a beginner race and it seemed that there were even greener riders than me. Nobody crashed, but there were certainly some moments that made me uncomfortable that could have been avoided.

Tour de Terra Cotta 2015 - Photo 1

Photo by jhbphotographs - View original on Flickr

Tour de Terra Cotta 2015 - Photo 2

Photo by jhbphotographs - View original on Flickr

Tour de Terra Cotta 2015 - Photo 3

Photo by jhbphotographs - View original on Flickr


older   →