diff --git a/README.md b/README.md
index ac78fd26c718bae91fb5c1bec45edab6632d9c0f..fba08404fcc521c6bfbbd5cffc91ece8c3752924 100644
--- a/README.md
+++ b/README.md
@@ -1,17 +1,17 @@
-# ws
+# websocket
 
-[![GoDoc](https://godoc.org/nhooyr.io/ws?status.svg)](https://godoc.org/nhooyr.io/ws)
-[![Codecov](https://img.shields.io/codecov/c/github/nhooyr/ws.svg)](https://codecov.io/gh/nhooyr/ws)
-[![GitHub release](https://img.shields.io/github/release/nhooyr/ws.svg)](https://github.com/nhooyr/ws/releases)
+[![GoDoc](https://godoc.org/nhooyr.io/websocket?status.svg)](https://godoc.org/nhooyr.io/websocket)
+[![Codecov](https://img.shields.io/codecov/c/github/nhooyr/websocket.svg)](https://codecov.io/gh/nhooyr/websocket)
+[![GitHub release](https://img.shields.io/github/release/nhooyr/websocket.svg)](https://github.com/nhooyr/websocket/releases)
 
-ws is a minimal and idiomatic WebSocket library for Go.
+websocket is a minimal and idiomatic WebSocket library for Go.
 
 This library is in heavy development.
 
 ## Install
 
 ```bash
-go get nhooyr.io/ws@master
+go get nhooyr.io/websocket@master
 ```
 
 ## Features
@@ -20,10 +20,9 @@ go get nhooyr.io/ws@master
 - Simple to use because of the minimal API
 - Uses the context package for cancellation
 - Uses net/http's Client to do WebSocket dials
-- JSON and Protobuf helpers in wsjson and wspb subpackages
-- Compression extension is supported
+- Compression of text frames larger than 1024 bytes by default
 - Highly optimized
-- API will be ready for WebSockets over HTTP/2
+- API will transparently work with WebSockets over HTTP/2
 - WASM support
 
 ## Example
@@ -33,28 +32,31 @@ go get nhooyr.io/ws@master
 ```go
 func main() {
 	fn := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
-		c, err := ws.Accept(w, r)
+		c, err := websocket.Accept(w, r,
+			websocket.AcceptSubprotocols("test"),
+		)
 		if err != nil {
 			log.Printf("server handshake failed: %v", err)
 			return
 		}
-		defer c.Close(ws.StatusInternalError, "")
+		defer c.Close(websocket.StatusInternalError, "")
 
 		ctx, cancel := context.WithTimeout(r.Context(), time.Second*10)
 		defer cancel()
 
-		err = wsjson.Write(ctx, c, map[string]interface{}{
+		v := map[string]interface{}{
 			"my_field": "foo",
-		})
+		}
+		err = websocket.WriteJSON(ctx, c, v)
 		if err != nil {
-			log.Printf("failed to write json struct: %v", err)
+			log.Printf("failed to write json: %v", err)
 			return
 		}
 
-		c.Close(ws.StatusNormalClosure, "")
+		log.Printf("wrote %v", v)
+
+		c.Close(websocket.StatusNormalClosure, "")
 	})
-	// For production deployments, use a net/http.Server configured
-	// with the appropriate timeouts.
 	err := http.ListenAndServe("localhost:8080", fn)
 	if err != nil {
 		log.Fatalf("failed to listen and serve: %v", err)
@@ -62,28 +64,33 @@ func main() {
  }
 ```
 
+For a production quality example that shows off the low level API, see the [echo example](https://godoc.org/nhooyr.io/websocket#ex-Accept--Echo).
+
 ### Client
 
 ```go
 func main() {
 	ctx := context.Background()
-	ctx, cancel := context.WithTimeout(ctx, time.Minute)
+	ctx, cancel := context.WithTimeout(ctx, time.Second*10)
 	defer cancel()
 
-	c, _, err := ws.Dial(ctx, "ws://localhost:8080")
+	c, _, err := websocket.Dial(ctx, "ws://localhost:8080",
+		websocket.DialSubprotocols("test"),
+	)
 	if err != nil {
 		log.Fatalf("failed to ws dial: %v", err)
 	}
-	defer c.Close(ws.StatusInternalError, "")
+	defer c.Close(websocket.StatusInternalError, "")
 
-	err = wsjson.Write(ctx, c, map[string]interface{}{
-		"my_field": "foo",
-	})
+	var v interface{}
+	err = websocket.ReadJSON(ctx, c, v)
 	if err != nil {
-		log.Fatalf("failed to write json struct: %v", err)
+		log.Fatalf("failed to read json: %v", err)
 	}
 
-	c.Close(ws.StatusNormalClosure, "")
+	log.Printf("received %v", v)
+
+	c.Close(websocket.StatusNormalClosure, "")
 }
 ```
 
@@ -111,10 +118,10 @@ https://github.com/gorilla/websocket
 This package is the community standard but it is very old and over timennn
 has accumulated cruft. There are many ways to do the same thing and the API
 overall is just not very clear. Just compare the godoc of
-[nhooyr/ws](godoc.org/github.com/nhooyr/ws) side by side with
+[nhooyr/websocket](godoc.org/github.com/nhooyr/websocket) side by side with
 [gorilla/websocket](godoc.org/github.com/gorilla/websocket).
 
-The API for nhooyr/ws has been designed such that there is only one way to do things
+The API for nhooyr/websocket has been designed such that there is only one way to do things
 and with HTTP/2 in mind which makes using it correctly and safely much easier.
 
 ### x/net/websocket
@@ -134,8 +141,8 @@ and clarity. Its just not clear how to do things in a safe manner.
 
 This library is fantastic in terms of performance though. The author put in significant
 effort to ensure its speed and I have tried to apply as many of its teachings as
-I could into nhooyr/ws.
+I could into nhooyr/websocket.
 
 If you want a library that gives you absolute control over everything, this is the library,
-but for most users, the API provided by nhooyr/ws will definitely fit better as it will
+but for most users, the API provided by nhooyr/websocket will definitely fit better as it will
 be just as performant but much easier to use.
diff --git a/accept.go b/accept.go
index 6ab95ee7528162b098c93dc57ad95100f217ca47..2e5c9e0bb25183ad0d13f176853a5dce2fdac9d9 100644
--- a/accept.go
+++ b/accept.go
@@ -1,4 +1,4 @@
-package ws
+package websocket
 
 import (
 	"fmt"
@@ -21,10 +21,11 @@ func AcceptSubprotocols(subprotocols ...string) AcceptOption {
 // AcceptOrigins lists the origins that Accept will accept.
 // Accept will always accept r.Host as the origin so you do not need to
 // specify that with this option.
+//
 // Use this option with caution to avoid exposing your WebSocket
 // server to a CSRF attack.
 // See https://stackoverflow.com/a/37837709/4283659
-// You can use a * to specify wildcards in domain names.
+// You can use a * to specify wildcards.
 func AcceptOrigins(origins ...string) AcceptOption {
 	panic("TODO")
 }
@@ -33,6 +34,7 @@ func AcceptOrigins(origins ...string) AcceptOption {
 // the connection to WebSocket.
 // Accept will reject the handshake if the Origin is not the same as the Host unless
 // InsecureAcceptOrigin is passed.
+// Accept uses w to write the handshake response so the timeouts on the http.Server apply.
 func Accept(w http.ResponseWriter, r *http.Request, opts ...AcceptOption) (*Conn, error) {
 	panic("TODO")
 }
diff --git a/datatype.go b/datatype.go
index 98e1a42ee695ba4d3c7ce9c42915860e9d0b213c..3fba0844ae9cc6fa4fc9d56a7e88e6070a966be6 100644
--- a/datatype.go
+++ b/datatype.go
@@ -1,4 +1,4 @@
-package ws
+package websocket
 
 // DataType represents the Opcode of a WebSocket data frame.
 //go:generate stringer -type=DataType
diff --git a/datatype_string.go b/datatype_string.go
index e4fdf8f7418f17f93a3b1b0e9377976b6d4e11ec..215340c3e8f9591c94d0b6b8e84da9413f77333b 100644
--- a/datatype_string.go
+++ b/datatype_string.go
@@ -1,6 +1,6 @@
 // Code generated by "stringer -type=DataType"; DO NOT EDIT.
 
-package ws
+package websocket
 
 import "strconv"
 
diff --git a/dial.go b/dial.go
index 36cb964b01ad489d98d2d619868875edde1f0081..361a8e5562c1330782beb7a7af2880ffe33cd9d5 100644
--- a/dial.go
+++ b/dial.go
@@ -1,4 +1,4 @@
-package ws
+package websocket
 
 import (
 	"context"
diff --git a/doc.go b/doc.go
index f54a122f77898780443e23a89a9a52375db0f4d1..cbec895a630594906ae9fd2e015d0369212c9c58 100644
--- a/doc.go
+++ b/doc.go
@@ -1,4 +1,4 @@
-// Package ws is a minimal and idiomatic implementation of the WebSocket protocol.
+// Package websocket is a minimal and idiomatic implementation of the WebSocket protocol.
 //
-// For now the docs are at https://github.com/nhooyr/ws#ws. I will move them here later.
-package ws
+// For now the docs are at https://github.com/nhooyr/websocket#websocket. I will move them here later.
+package websocket
diff --git a/example_test.go b/example_test.go
index e37a390b60d37be6526700342dc8ff47488716a1..0b15fab7b927d9b7d80d4cda34d9d4f5e546f691 100644
--- a/example_test.go
+++ b/example_test.go
@@ -1,4 +1,4 @@
-package ws_test
+package websocket_test
 
 import (
 	"context"
@@ -9,20 +9,19 @@ import (
 
 	"golang.org/x/time/rate"
 
-	"nhooyr.io/ws"
-	"nhooyr.io/ws/wsjson"
+	"nhooyr.io/websocket"
 )
 
 func ExampleAccept_echo() {
 	fn := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
-		c, err := ws.Accept(w, r,
-			ws.AcceptSubprotocols("echo"),
+		c, err := websocket.Accept(w, r,
+			websocket.AcceptSubprotocols("echo"),
 		)
 		if err != nil {
 			log.Printf("server handshake failed: %v", err)
 			return
 		}
-		defer c.Close(ws.StatusInternalError, "")
+		defer c.Close(websocket.StatusInternalError, "")
 
 		ctx := context.Background()
 
@@ -65,9 +64,14 @@ func ExampleAccept_echo() {
 			}
 		}
 	})
-	// For production deployments, use a net/http.Server configured
-	// with the appropriate timeouts.
-	err := http.ListenAndServe("localhost:8080", fn)
+
+	s := &http.Server{
+		Addr:         "localhost:8080",
+		Handler:      fn,
+		ReadTimeout:  time.Second * 15,
+		WriteTimeout: time.Second * 15,
+	}
+	err := s.ListenAndServe()
 	if err != nil {
 		log.Fatalf("failed to listen and serve: %v", err)
 	}
@@ -75,28 +79,31 @@ func ExampleAccept_echo() {
 
 func ExampleAccept() {
 	fn := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
-		c, err := ws.Accept(w, r)
+		c, err := websocket.Accept(w, r,
+			websocket.AcceptSubprotocols("test"),
+		)
 		if err != nil {
 			log.Printf("server handshake failed: %v", err)
 			return
 		}
-		defer c.Close(ws.StatusInternalError, "")
+		defer c.Close(websocket.StatusInternalError, "")
 
 		ctx, cancel := context.WithTimeout(r.Context(), time.Second*10)
 		defer cancel()
 
-		err = wsjson.Write(ctx, c, map[string]interface{}{
+		v := map[string]interface{}{
 			"my_field": "foo",
-		})
+		}
+		err = websocket.WriteJSON(ctx, c, v)
 		if err != nil {
-			log.Printf("failed to write json struct: %v", err)
+			log.Printf("failed to write json: %v", err)
 			return
 		}
 
-		c.Close(ws.StatusNormalClosure, "")
+		log.Printf("wrote %v", v)
+
+		c.Close(websocket.StatusNormalClosure, "")
 	})
-	// For production deployments, use a net/http.Server configured
-	// with the appropriate timeouts.
 	err := http.ListenAndServe("localhost:8080", fn)
 	if err != nil {
 		log.Fatalf("failed to listen and serve: %v", err)
@@ -108,18 +115,21 @@ func ExampleDial() {
 	ctx, cancel := context.WithTimeout(ctx, time.Minute)
 	defer cancel()
 
-	c, _, err := ws.Dial(ctx, "ws://localhost:8080")
+	c, _, err := websocket.Dial(ctx, "ws://localhost:8080",
+		websocket.DialSubprotocols("test"),
+	)
 	if err != nil {
 		log.Fatalf("failed to ws dial: %v", err)
 	}
-	defer c.Close(ws.StatusInternalError, "")
+	defer c.Close(websocket.StatusInternalError, "")
 
-	err = wsjson.Write(ctx, c, map[string]interface{}{
-		"my_field": "foo",
-	})
+	var v interface{}
+	err = websocket.ReadJSON(ctx, c, v)
 	if err != nil {
-		log.Fatalf("failed to write json struct: %v", err)
+		log.Fatalf("failed to read json: %v", err)
 	}
 
-	c.Close(ws.StatusNormalClosure, "")
+	log.Printf("received %v", v)
+
+	c.Close(websocket.StatusNormalClosure, "")
 }
diff --git a/go.mod b/go.mod
index 4749de6dca2e412095dadd31e737b9fe3425fe3b..60d1a3d0f432ec36f998138b76bd45979c55848d 100644
--- a/go.mod
+++ b/go.mod
@@ -1,9 +1,8 @@
-module nhooyr.io/ws
+module nhooyr.io/websocket
 
 go 1.12
 
 require (
-	github.com/golang/protobuf v1.3.1
 	github.com/kr/pretty v0.1.0 // indirect
 	go.coder.com/go-tools v0.0.0-20190317003359-0c6a35b74a16
 	golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3
diff --git a/go.sum b/go.sum
index b5d8f2fc56742d71fafbab10559ce86f24d31236..efb01309f0333453695cddc3df942598a95c1fdf 100644
--- a/go.sum
+++ b/go.sum
@@ -1,5 +1,3 @@
-github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg=
-github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
 github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
 github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
 github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
diff --git a/header.go b/header.go
index 42eb6143deeca179b62648ff1c8e334405a6ea5a..d6fdfc75cb840bf176fba452e1dd7c65b3954fda 100644
--- a/header.go
+++ b/header.go
@@ -1,4 +1,4 @@
-package ws
+package websocket
 
 import (
 	"io"
diff --git a/json.go b/json.go
new file mode 100644
index 0000000000000000000000000000000000000000..f570499b558ef0f42b0c684c72e8858c0cbef72e
--- /dev/null
+++ b/json.go
@@ -0,0 +1,15 @@
+package websocket
+
+import (
+	"context"
+)
+
+// ReadJSON reads a json message from c into v.
+func ReadJSON(ctx context.Context, c *Conn, v interface{}) error {
+	panic("TODO")
+}
+
+// WriteJSON writes the json message v into c.
+func WriteJSON(ctx context.Context, c *Conn, v interface{}) error {
+	panic("TODO")
+}
diff --git a/mask.go b/mask.go
index e3679cb860994d7d00eec4833eedc7404b7e6fa6..795d3660636bc1e33a760bef44540da110afc88f 100644
--- a/mask.go
+++ b/mask.go
@@ -1,4 +1,4 @@
-package ws
+package websocket
 
 // Mask applies the WebSocket masking algorithm to p
 // with the given key where the first 3 bits of pos
diff --git a/opcode.go b/opcode.go
index 5616bb578b15bbbebcd6531aef73545ede875202..d7eebbff13c6cd1049c0b5fbf926c719f5b04b3c 100644
--- a/opcode.go
+++ b/opcode.go
@@ -1,4 +1,4 @@
-package ws
+package websocket
 
 // opcode represents a WebSocket Opcode.
 //go:generate stringer -type=opcode
diff --git a/opcode_string.go b/opcode_string.go
index 84afd17a09da3f4a5a33ee219a099a9dd83b5d1f..e815cdea869072f5fd89caeb607d2e4a606b57e1 100644
--- a/opcode_string.go
+++ b/opcode_string.go
@@ -1,6 +1,6 @@
 // Code generated by "stringer -type=opcode"; DO NOT EDIT.
 
-package ws
+package websocket
 
 import "strconv"
 
diff --git a/statuscode.go b/statuscode.go
index 5ceb24ac60fddf62bc013ced4aee7f542e752b26..d53723609a4b25d426b5b7019afdb05a0395962c 100644
--- a/statuscode.go
+++ b/statuscode.go
@@ -1,4 +1,4 @@
-package ws
+package websocket
 
 import (
 	"encoding/binary"
diff --git a/statuscode_string.go b/statuscode_string.go
index 2d4ab76502bc2b00f28972b75774e4f29afaac63..e1bfc4629bcc3ce03f0bba4236bde61c268c1c50 100644
--- a/statuscode_string.go
+++ b/statuscode_string.go
@@ -1,6 +1,6 @@
 // Code generated by "stringer -type=StatusCode"; DO NOT EDIT.
 
-package ws
+package websocket
 
 import "strconv"
 
diff --git a/ws.go b/websocket.go
similarity index 99%
rename from ws.go
rename to websocket.go
index 964a31843e332ba9d12f2f5adf02a5fe70071cd1..b57b685e73600543fb404224859e556ee8148b8e 100644
--- a/ws.go
+++ b/websocket.go
@@ -1,4 +1,4 @@
-package ws
+package websocket
 
 import (
 	"context"
diff --git a/wsjson/wsjon.go b/wsjson/wsjon.go
deleted file mode 100644
index 33dc0154b75df711c58455f5d147e4568e1fc7ca..0000000000000000000000000000000000000000
--- a/wsjson/wsjon.go
+++ /dev/null
@@ -1,17 +0,0 @@
-package wsjson
-
-import (
-	"context"
-
-	"nhooyr.io/ws"
-)
-
-// Read reads a json message from c into v.
-func Read(ctx context.Context, c *ws.Conn, v interface{}) error {
-	panic("TODO")
-}
-
-// Write writes the json message v into c.
-func Write(ctx context.Context, c *ws.Conn, v interface{}) error {
-	panic("TODO")
-}
diff --git a/wspb/wspb.go b/wspb/wspb.go
deleted file mode 100644
index 9c7b1549f2dbdf3ab5d83ab7dccbf40a7f596fa7..0000000000000000000000000000000000000000
--- a/wspb/wspb.go
+++ /dev/null
@@ -1,19 +0,0 @@
-package wspb
-
-import (
-	"context"
-
-	"github.com/golang/protobuf/proto"
-
-	"nhooyr.io/ws"
-)
-
-// Read reads a protobuf message from c into v.
-func Read(ctx context.Context, c *ws.Conn, v proto.Message) error {
-	panic("TODO")
-}
-
-// Write writes the protobuf message into c.
-func Write(ctx context.Context, c *ws.Conn, v proto.Message) error {
-	panic("TODO")
-}