all: use make to build

This overhauls the build system.
We used to use a just-in-time clever build system
so that 'go run' and 'go install' Just Worked.

This was really nice, except that it make it
all but impossible to ship a single binary.
It also required our uses to install npm,
which some folks have an understandably negative reaction to.

This migrates to a makefile for building.
The core typescript building logic is mostly still in Go,
and untouched (boy did I learn that lesson the hard way).

The output is a single file that includes the webui, innie, and outie.

(There are still very mild shenanigans in which we write outie
out to a temp file and then 'docker cp' it into the docker container.
But this is pretty manageable.)

There are some significant follow-ups left after this commit:

- convert the nightly release builds to use the makefile
- lots of dead code removal
- maybe add -race support using a dockerfile for the cgo compilation
- maybe use 'docker cp' stdin reading with tar to avoid the temp outtie file
- all the rest of the "better release" todos (brew install, etc.)
diff --git a/cmd/genwebui/genwebui.go b/cmd/genwebui/genwebui.go
new file mode 100644
index 0000000..2abe552
--- /dev/null
+++ b/cmd/genwebui/genwebui.go
@@ -0,0 +1,29 @@
+package main
+
+import (
+	"flag"
+	"log"
+	"os"
+
+	"sketch.dev/webui"
+)
+
+func main() {
+	flag.Parse()
+	if flag.NArg() != 1 {
+		log.Fatalf("expected exactly 1 arg (destination directory), got %v", flag.NArg())
+	}
+	dest := flag.Arg(0)
+	if dest == "" {
+		log.Fatalf("expected destination directory, got %q", dest)
+	}
+	// TODO: make webui.Build write directly to dest instead of writing to a temp dir and copying to dest
+	fsys, err := webui.Build()
+	if err != nil {
+		log.Fatal(err)
+	}
+	err = os.CopyFS(dest, fsys)
+	if err != nil {
+		log.Fatal(err)
+	}
+}
diff --git a/cmd/genwebuizip/genwebuizip.go b/cmd/genwebuizip/genwebuizip.go
deleted file mode 100644
index 02602b6..0000000
--- a/cmd/genwebuizip/genwebuizip.go
+++ /dev/null
@@ -1,33 +0,0 @@
-package main
-
-import (
-	"flag"
-	"fmt"
-	"log"
-	"os/exec"
-	"path/filepath"
-
-	"sketch.dev/webui"
-)
-
-func main() {
-	dest := flag.String("dest", ".", "destination directory")
-	flag.Parse()
-
-	// Make sure that the webui is built so we can copy the results to the container.
-	_, err := webui.Build()
-	if err != nil {
-		log.Fatal(err.Error())
-	}
-
-	webuiZipPath, err := webui.ZipPath()
-	if err != nil {
-		log.Fatal(err.Error())
-	}
-	cmd := exec.Command("cp", webuiZipPath, filepath.Join(*dest, "."))
-	if err := cmd.Run(); err != nil {
-		log.Fatal(err.Error())
-	}
-
-	fmt.Printf("webuiZipPath: %v copied to %s\n", webuiZipPath, *dest)
-}
diff --git a/cmd/sketch/main.go b/cmd/sketch/main.go
index 587a6b1..21e569b 100644
--- a/cmd/sketch/main.go
+++ b/cmd/sketch/main.go
@@ -38,12 +38,13 @@
 	"sketch.dev/webui"
 )
 
-// Version information set by GoReleaser at build time
+// Version information set by ldflags at build time
 var (
-	version = "dev"     // version string
-	commit  = "none"    // git commit hash
-	date    = "unknown" // build timestamp
-	builtBy = "unknown" // who built this binary
+	version  = "dev"     // version string
+	commit   = "none"    // git commit hash
+	date     = "unknown" // build timestamp
+	builtBy  = "unknown" // who built this binary
+	makefile = ""        // marker indicating a makefile build
 )
 
 func main() {
@@ -59,6 +60,11 @@
 func run() error {
 	flagArgs := parseCLIFlags()
 
+	// If not built with make, embedded assets will be missing.
+	if makefile == "" {
+		return fmt.Errorf("please use `make` to build sketch")
+	}
+
 	// Set up signal handling if -ignoresig flag is set
 	if flagArgs.ignoreSig {
 		setupSignalIgnoring()