Tuesday, September 26, 2017

p5 editor to programmatically make a downloadable image in the browser

QUICK HACK: I have a lot of decent art programs for my iPad, but it seems like like such programs no longer come with tools for making simple shapes, like circles and squares. That made my inner child a little sad! Paint programs used to be fun, you know? Like just tooling around throwing shapes and patterns on the screen...

It's tough enough to find programs with flood fill, actually.... it seems like almost every art program is either imitating "real" art tools, aimed at photo retouching, or tries to get you to think in their weird interface for vectors.

Anyway, I wanted a colored circle as a base for a Jack-O-Lantern tuba cover I'm making, and the easiest way was to go to the online p5 editor and enter the following:

function setup() { 
  createCanvas(3000, 3000);
noSmooth();


function draw() { 
  background(255);
noStroke();
fill(255,140,0);
ellipse(1500,1500,2500,2500);
saveCanvas("art.png");
noLoop();
}

That actually generates a file "art.png" which the browser will offer to download.
I then used Dropbox to transfer it to my iPad.

UPDATE:  Did a bit more work...

So, I'm making up designs for tuba covers (as printed by the fine folks at http://stretchablecovers.net/) Before I mentioned the first step for a Jack-O-Lantern (drawn in by hand)

But a few years ago I had a DIY craft project (felt crudely stapled onto the blank side of a cover) skull for my tuba:


I lost it in my recent move, and decided I'd get it printed up, and that I'd use another p5.js program to do it. (I liked the idea of using shapes rather than being quite hand drawn).

Net, net, you can see and play with the p5.js program here. The moderately clever bit is using a technique to let me finesse the placement of a piece via "map()"ing the X and Y mouse position to appropriate values, and then building a string for the corresponding ellipse() or line() command. I then both print the screen and run javascript's "eval()" on it. Once I get the fragement where I like it, I copy and paste the printed version of the statement and place it into the code, so it's kind of baked into the place and then I repeat the technique for the next fragment.


Oh, also for funsies check out my old Carve Your Own Jack-O-Lantern Processing Program... very similar in spirit to all this.

For reference (since I guess I shouldn't an  account on a "alpha version" editor as a code repository) here is the code... it's not (quite) as hackish as it looks.

var BASE;
var s;
function setup() { 
  BASE = 30;// random(38,58);
  createCanvas(BASE*10, BASE*10);
strokeCap(SQUARE);


function draw() { 
  //BASE += random(-.1,.1);
  background(200);
noStroke();
translate(width/2,height/2);
fill(255);
ellipse(0,0,BASE*8,BASE*8);
fill(0);
push();
  var f1 = map(mouseX,0,width, -5,5).toFixed(3);;
  var f2 = map(mouseY,0,height, -5,5).toFixed(3);
  var s;
//var s = "bigEye("+f1+","+f2+");";
  s = "bigEye(1.835,-1.239);";
  eval(s);
  s = "nose(-1.867,0.824)";
  eval(s);
  
  //s = "smallEye("+f1+","+f2+")";
  s = "smallEye(-2.037,-0.947)";
  eval(s);
  
  s = "mouth()";
  eval(s);
  
  s = "crack("+f1+","+(f2)+");"
  eval(s);


}

function mousePressed(){
  noLoop(); 
}

function crack(a,b){
    strokeWeight(BASE/5);
  stroke(0);
  noFill();
  push();
 // print (a+":"+b);
  translate(BASE*.137,BASE*.44);
beginShape();
  push();
 vertex(BASE*-3.392,BASE*-4.471);
vertex(BASE*-1.704,BASE*-3.673);
vertex(BASE*-1.367,BASE*-3.895);
vertex(BASE*-1.316,BASE*-3.14);
vertex(BASE*-0.497,BASE*-3.36);
  vertex(BASE*0.084,BASE*-2.65);
//vertex(BASE*-0.894,BASE*-2.657);
vertex(BASE*-0.497,BASE*-3.36);
  vertex(BASE*0.143,BASE*-3.791);

  s = "vertex(BASE*"+a+",BASE*"+b+");";
 // eval(s);
 // print(s);
  endShape();
  pop();
  
  
    noLoop(); 
 saveCanvas("skull.png");

}


function mouth(){
  strokeWeight(BASE/2.8);
  stroke(0);
  line(-BASE*4,BASE*2,BASE*4,BASE*2);
  
  line(0,BASE*1.35,0,BASE*2.65);
  line(-BASE,BASE*1.45,-BASE,BASE*2.55);
  line(-2*BASE,BASE*1.4,-2*BASE,BASE*2.55);
  line(BASE,BASE*1.45,BASE,BASE*2.65);
  line(2*BASE,BASE*1.45,2*BASE,BASE*2.55);
}



function nose(a,b){
  push();
  push();
  rotate(a);
  ellipse(0,BASE/4,BASE*2,BASE);
  pop();
  push();
  rotate(-a);
  ellipse(0,+BASE/4,BASE*2,BASE);
  pop();
}

function bigEye(f1,f2){
  var g = 2.5;
  push();
  translate(f1* BASE,f2*BASE);
rotate(0.1);
  ellipse(0,0,BASE*g,BASE*g*1.3);
pop();
}

function smallEye(f1,f2){
  var g = 2.2;
  push();
  translate(f1* BASE,f2*BASE);
rotate(0.1);
  ellipse(0,0,BASE*g*1.1,BASE*g);
pop();
}

Monday, September 25, 2017

json junk

Heh, JSON Generator is a cool way of making fake-y data that follows your JSON structures...

Wednesday, September 20, 2017

trivial php router for local dev and under apache

I wanted to make a PHP app so that I could work on it online and offline, with or without Apache, and that maybe it would be cool to have a centralized controller... do things a bit MVCishly rather than just having a pile of .php scripts (in particular, my first attempt for chart-o-tron did a lot of htaccess hackery to allow for pretty URLs, but the other URLs were all .php which looks pretty janky these days)

The page on the PHP built-in webserver mentions you can run PHP from the command line, and have every request be piped into a router
php -S localhost:8000 router.php
and here's their sample router script:
<?php
// router.php
if (preg_match('/\.(?:png|jpg|jpeg|gif)$/', $_SERVER["REQUEST_URI"])) {
    return false;    // serve the requested resource as-is.
} else { 
    echo "<p>Welcome to PHP</p>";
}
?>
The trouble was when I setup .htaccess to have Apache send all requests to it, the idea of "return false;" doesn't mean anything when Apache has already ceded control. In theory I could have used readfile() to handle PHP stream up static files, but it seemed weird, not leveraging Apache's optimization in serving static content, and a potential security weakpoint.

I decide to put all my static content under /static/ rather than worry about file extensions, or regular expressions to tell Apache to treat .php files differently... It took some fumbling to get the regex quite right:
RewriteEngine On
RewriteRule !^static router.php [L]

I then fiddled with the router script to do the parallel thing when I'm running locally:
<?php
if (preg_match('/^\/static\//', $_SERVER["REQUEST_URI"])) {
    return false;    // serve the requested resource as-is.
} else { 
    echo "<p>Welcome to PHP</p>".$_SERVER["REQUEST_URI"];
}
?>
Seems like a good start. There are other PHP router scripts that are configurable, but I kind of like this low level of control. 

farewell 32-bit iOS apps...

Well, we knew this day was coming... with the release of iOS11, Apple is dropping support for 32-bit apps. I can't blame them, entirely - eventually a company should probably decide to drop the technical weight of supporting everything forever. Still messages like "'ThisApp' May Slow Down Your iPhone" "If no update is available, contact the app developer for more information" were kind of disingenuous. It's stretching it to say it "slowed down the phone" - it would take a moment to setup the legacy libraries, and it's less memory efficient, but really the transition was seamless.

But contact the developer? As if the problem was they didn't know... more "nag the developer and hope that they care about this app even though they didn't figure out how to make it financially viable on an ongoing basis".

If you want to find out what apps you might lose if/when you upgrade to iOS11, go to Settings App, General | About | Applications.

The damage was less bad for me personally than I had feared. I just wanted to take a second to note the apps as I say farewell...

GAMES I'LL MISS

  • ENDI Tank was a playful 3D tank game, taking place in a sandbox. Seems to be a student game, from the École Nationale de Divertissement Interactif , but it was nicely balanced and looked great.
  • Little Master Cricket is a simple physics game from the maker of QWOP. I guess you can play it online (if you still run Flash anyway... sigh.) - balls got pitched in and your batsman had to hit them away and protect the wicket, or whatever cricket is about. It was a fun quick-hit.
  • Truckers was a raucous 16-bit-graphic-flavored semi-driving romp, a bit like Outrun. It's so well polished that I'm surprised it never saw an update. 
  • Big Fat Lies was one of the best "entertain people incuding the driver" car games I've seen. A bit like that part of "Wait Wait Don't Tell Me", two outlandish stories would appear and the current player would have to say which one was false.
  • Galcon was a primitive but fun 2D Real Time Strategy game that I've seen on many platforms, send your hoardes of triangular spaceships to take over planet by planet, turning each into a ship manufacturer to increase the size of your fleet. It was kind of inspiring because I knew it was written in Python/PyGame, back when I thought everything for iPhone had to be in ObjectiveC.
UTILITIES I'LL MISS
  • Weightbot was a terrific little weight tracking tool that made nice little bloops and blurps and clicky noises as you entered your weight. I was using it from 2010 'til this year. Now I use "Weight Record", which has a very similar vibe, but isn't as cute, and with much less satisfying clicks.
  • You've Gotta See This! was a fine bit of photo-stitch software, using the then-new gyroscope to let you wave around the camera and then put together panoramas of the result:
    I have a few similar programs, but haven't yet searched to see if anything does quite as well as this one.
So apps I won't miss: Cracked - "Cracked Lite" has been superior for a long time for reading that great content. CanIStream.it I guess duplicates the website functionality which hasn't felt trustworthy in a while. 20 Questions was another car-able game, mostly just a collection of words to guess. That just leaves iMetronomeTempoTool (heh, kind of a port of an app I wrote for Palm PocketC to tell me what the current BPM are) and SimpleResize - I think these are all utilities I can find replacements for if/when the need arises.

With today's curated online appstores, digital archiving becomes harder and harder- a harsh reality for a lazy retrogamer like myself. Even before this great 32-bit-app purge, there was a great 2D Tank game called "Tron" that Disney commissioned when the new movie came out that has been AWOL for a while. And it's not just Apple - even on Xbox Live, there's a Doritos-sponsored game called "Dash of Destruction" that had such fun with scale - playing on the same board as either a GIANT dinosaur or a tiny delivery van - but if anything ever happens to my hardware I'll probably lose access to the game. For digital historians it's a tough road to hoe.

Monday, September 18, 2017

syntactic high-fructose corn syrup

It's easy for old fogies like me to get a bit cynical about ES6 and all the new syntactic sugar - it can be tough to pick up because if you've only seen it in a webinar or two, but it's not prevalent in the legacy code base you're working with daily, it's easy to forget, and then confusing when you do run into it.

Case in point, this line:
const { urls = {} } = window || {};

Roughly it's saying "set a constant variable (ok, a 'constant') called urls to window.urls if it exists, but don't blow up if window or window.urls doesn't exist."

Besides recognize const vs var, there are three things going on in that tangle:
  1. The good old fashioned, pre-ES6 "short circuit" operator, where you can say
    something = thatthing || {};
    so the right side is thatthing if thatthing is truthy-true otherwise, set to an empty map.

    (huh, surprised the people who love triple equals haven't made triple-or to specifically handle "if this is null or undefined")
  2. Destructuring! The simple case here would be if you had an object called foo with a key bar set to something and a key baz set to something. Then you could say
    var {bar,baz} = foo;
    to get a local var bar and a local var baz set to foo.bar and foo.baz, respectively.

    This actually neatly addresse a weird asymmetry in C-style syntax I blogged about 13 years ago - that it's strange that you pass many things into a function, but you only get one thing out. But now you can do
    var {oneThing, anotherThing} = someFunctionCall();
    and you don't have extract simple variables out of a map object by hand.
  3. Default parameters - for a second
    {urls = {}}
    seemed so strange... I mean I see the value of saying "set urls equal to this if all else fails" but was it a special, one-off syntax just for destructuring? Well, no, now that I think about it... in ES6 you can have
    function someFunc(someParamWithADefault="that default"){ 
    and if nothing is passed in for that first parameter, the first parameter becomes that default. And so we see the syntax used inside the destructuring assignment is borrowing from that generalized default parameter shortcut
So thanks to Dan at work who wrote the code and then explained it to me nicely when asked... he also pointed out I can go to this Babel.js tool to see the concise syntax translated into old school javascript.... in this case
  const { urls = {} } = window || {};becomes

"use strict";
var _ref = window || {},
    _ref$urls = _ref.urls,
    urls = _ref$urls === undefined ? {} : _ref$urls; 
Still a little tough to digest, but it's nice to be able to trace the steps. 

So it seems like Javascript is borrowing the Perl idea of "lets say this more concisely with nifty syntaxes!" but missing Perl's "lets not blow up if we try to pull a value out of an object that doesn't really exist". 

Sunday, September 10, 2017

put something back into the world

Steve Jobs over dinner with Steven Levy:
"I look at myself as [sort of trapeze artist, without a net] if anything. But it's a way of expressing feelings about, a group of feelings. Wanting to put something back into the world. You know we're constantly taking. We don't make most of the food we eat, we don't grow it, anyway. We wear clothes other people make, we speak a language other people developed, we use a mathematics other people evolved and spent their lives building. I mean we're constantly taking things. It's a wonderful ecstatic feeling to create something and put it into the pool of human experience and knowledge.
The interview transcript is an appendix to a new edition of his older book about the development of the Macintosh, "Insanely Great"

One thing the book mentioned was John Sculley pricing the late-80s Mac a bit high, going for profit margin rather than marketshare. I guess a version of that strategy is working well for Apple now, taking something like 90% of the mobile phone industry profits, but still visions of a world where the Mac had early, Apple II like penetration, and where every college kid had one rather than just the artsy ones... if HyperCard had been in the hands of even more people...

(Of course, looking around in the environs of Boston tech and Cambridge coffeeshops, it's astounding that only 1 in 10 PCs are by Apple - they seem to be omnipresent)

Getting back to the Steve Jobs quote, thinking of what I try to add to that pool. I guess except for "JoustPong" (heh) my best bet is helping people to calm down about death via So, You're Going to Die.


Sunday, September 3, 2017

css-only icons

Keeping my eyes open for icon packs that are cheap, both in terms of complexity/files to load, and in terms of cost (though i don't mind spending $10 or so I guess.)

Icono pure CSS icons are pretty dope, but it's weird there's no obvious "edit" (like maybe a pencil to a piece of paper?) Also they're not easy to resize I guess. Maybe I should keep looking for future projects, but for my current project it'll do.

Saturday, September 2, 2017

i teach you the spongeman

A while ago my erstwhile debating partner introduced me to Rapoport's Rules, guidelines for criticizing the argument of an opponent. As formulated by my favorite philosopher Daniel Dennett, they go:
  1. You should attempt to re-express your target’s position so clearly, vividly, and fairly that your target says, "Thanks, I wish I’d thought of putting it that way."
  2. You should list any points of agreement (especially if they are not matters of general or widespread agreement).
  3. You should mention anything you have learned from your target.
  4. Only then are you permitted to say so much as a word of rebuttal or criticism.
Another term for this is "steelmanning" - in contrast to "strawmanning", where you knock down a lightweight representation of the opposing argument that's designed to be knocked down, here you make an effort to really understand and then gird it in rhetorical steel and state it back to them.

On some levels the rules' concept is appealing, but also - unlikely, I guess I'd say, for people who have are arguing sincerely. If you could whole-heartedly restate your partner's (or as the rules put it, "target's") view, you'd pretty much have to be believing it yourself. That "Thanks, I wish I'd thought of putting it that way" bit is also weirdly condescending - your displayed mastery of the domain is such that your "target" will humbly thank you for your cleverness of the restatement? For something that you still don't believe? What kind of insincere sophistry is that? Like a suit of armor, I think this kind of steelman will ring hollow.

My erstwhile buddy didn't really grasp my objections until he listened to Hannibal Buress on the Sam Harris podcast. (Admittedly Buress might be a little drunk, but I appreciate his sincere points) Around 29:00 minutes in, Sam Harris says
Here's a bet, here's a bet: I could summarize your view of me in a way that you'd agree with. You couldn't return the favor. You want to take that bet? I'm absolutely sure I can articulate how you view your side of the conversation in a way that you'd sign off on. I have absolutely no faith that you could do the same for me. That's a problem, we're not successfully communicating.
My buddy had an even strong reaction against Harris there than I did, that he saw Harris using the "I can see your side" concept as a bludgeon.

My counter-proposal was "spongemanning". The best we can do is try to absorb the other person's argument, then wring ourselves out, restating the argument as best we can, and have our partner comment on the drippings, to see how much of the salient info we had actually taken in. Spongemanning offers more substance than the superficialities of steelmanning, and it is more respectful than steelmannings "anything you can think, I can think better".

At its very best it invites participants to think about where their partner is coming from, and what are the headwaters of their current flow. (At the risk of straining the wet metaphor.) One of the few things I like about Ayn Rand is her alleged greeting of "What are your premises?" It's rather belligerent, but it gets to the heart of why sincere people who keep faith in the methods of rationality and discourse as a way of understanding the universe can still disagree... they have different starting assumptions and then differing concepts on what is best prioritized in life. By trying to absorb what your opponent is saying, you might better identify and catalog those sticking points - fundamental areas of disagreement where "agreeing to disagree" isn't throwing out the whole kit and kaboodle.

Behold: the spongeman! (With normal, double-tube-shaped pants)