By mistake, MySpace inspired a generation of teenagers to learn how to code. From Stealing MySpace:

But Nguyen forgot to block Web markup language in user submissions.
His mistake allowed users to build colorful backgrounds and wallpapers and load them onto their MySpace pages.

The internet used to be fun and weird.

During the internet of 2006, consumer products let anyone edit CSS. It was a beautiful mess. As the internet grew up, consumer products stopped trusting their users, and the internet lost its soul.

When's the last time a consumer product let you do this?

Normal
📫 gmail invite code
🦉O RLY?
❗️SHOUTING!!
→ Tilt this


We have Dark Mode now...

But where did all the glitter go?

Today's internet is Serious Business.

When MySpace was a thing, the internet was just a series of tubes. People used it to buy beanie babies and play Runescape.

That changed. The internet of 2019 is vital societal infrastructure. We depend on it to keep in touch with family, to pay for things, and so much more.

Just because it got serious doesn't mean it can't be fun and weird.

Three things MySpace got right

1. To make a page on MySpace, all it took was text in a textbox.

2. The text could be words or code.

3. Anyone could read the words and see the code.



MySpace's simplicity enabled teenagers to make silly things like glitter text, custom layouts and more. MySpace profiles were a canvas for self-expression and code was the paint.

MySpace showed the world that if you make powerful and complicated tools (like coding) accessible to anyone, people are smart enough to figure out how to use them.

The lesson the internet learned? No thanks.

We started sanitizing inputs. This remains a huge win for security. But, that means sticking code and words in the same place doesn't work anymore. The code becomes ordinary words...or nothing at all.

Nobody ever talks about why this was bad for the world.

Coding became a privilege, instead of a right.

The internet is the great equalizer (1996). People used to believe that. Today, it sounds sarcastic.

We — the programmers, designers, product people — collectively decided that users don't deserve the right to code in everyday products. Users are too stupid. They'd break stuff. Coding is too complicated for ordinary people. Besides, we can just do the coding...so why does it matter?

The internet added <canvas />, but the internet stopped being one.



2019, a world where all the apps are the same.

Facebook, WhatsApp, Messenger, and Instagram are merging. Instagram cloned Snapchat, and Twitter is just screenshots on Instagram.

The everyday consumer products are converging. They ran out of good ideas for helping people express themselves, so all that's left is to monopolize.

Introducing Codeblog

Codeblog makes coding as easy as blogging. It's an open-source blogging platform where, instead of just words, you can also write code that runs in the blog post.

For example, even though HTML lacks a <Glitter /> tag, Codeblog lets me write Glitter text.

HTML doesn't have a <ConfettiButton /> tag either, but Codeblog makes it easy to add it to my post.

🎉 Confetti me

You're reading a codeblog now.

Posts are written in a flavor of Markdown that renders React components inline. This makes writing words feel natural and writing JavaScript feel like HTML.

You can write and publish posts directly on codeblog.com without downloading anything, or you can use your text editor. Host your codeblog for free on codeblog.com, or you can host it yourself.

Codeblog is powered by MDX, a new flavor of Markdown that supports JSX. With MDX, words look like words, and code looks like HTML.

- Post online. Write & publish posts on codeblog.com or write from your text editor.

- Social coding. Post comments with words or code and follow codeblogs. It's the easiest way to show stuff you're working on. Or just rant.

- Plugins. Auto-install npm packages as you use them. Through npm, Codeblog will support hundreds of thousands of plugins from day one.

- Free hosting via codeblog.com, or you can self-host.

One more thing.

When you publish a component on Codeblog, anyone else can instantly use it. The source code for components are public by default. Here's the source code for the code snippet component:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180

import * as React from "react";
import { css } from "@emotion/core";
import SyntaxHighlighter from "react-syntax-highlighter";

const CodeBlockCSS = css`
  position: relative;
  .hljs {
    direction: ltr;
    text-align: left;
    word-spacing: normal;
    word-break: normal;
    white-space: pre;
    overflow: auto;
    max-height: 500px;
    line-height: 1.2;
    tab-size: 2;
    padding: var(--offset-medium);
    background-color: var(--text-dark-color);
    color: var(--page-background);
    hyphens: none;
    border-radius: var(--border-radius);
    font-size: 16px;
    font-family: var(--monospace-font);
    -webkit-mask-image: radial-gradient(
      circle,
      var(--page-background) 100%,
      var(--text-dark-color) 100%
    );
    -moz-mask-image: radial-gradient(
      circle,
      var(--page-background) 100%,
      var(--text-dark-color) 100%
    );
  }
  @media (max-width: 500px) {
    .hls {
      max-height: 800px;
    }
  }
  .hljs::-webkit-scrollbar-track {
    background-color: #222;
  }
  .hljs::-webkit-scrollbar {
    height: 12px;
    width: 12px;
    opacity: 0.5;
  }
  .hljs::-webkit-scrollbar-thumb {
    background-color: var(--page-background);
    border: 3px solid #222;
    border-radius: 10px;
  }
  .hljs * {
    background: unset !important;
  }
  .hljs code:first-of-type {
    user-select: none;
    -webkit-user-select: none;
  }
  .hljs code + code {
    margin-left: var(--offset-medium);
    display: block;
  }
  .react-syntax-highlighter-line-number {
    color: #827d82;
  }
  /* ---- Syntax highlighting ---- */
  .hljs .tag,
  .hljs .string,
  .hljs .meta,
  .hljs .symbol,
  .hljs .template-tag,
  .hljs .template-variable,
  .hljs .addition {
    color: #769fff;
    font-weight: normal;
  }
  .hljs .punctuation,
  .hljs .comment,
  .hljs .quote {
    color: #827d82;
  }
  .hljs .number,
  .hljs .regexp,
  .hljs .literal,
  .hljs .link {
    color: #31a354;
  }
  .hljs .deletion,
  .hljs .variable {
    color: #7e9eff;
    font-weight: normal;
  }
  .hljs .keyword,
  .hljs .operator {
    color: #ff6c6c;
  }
  .hljs .function {
    color: #d46dff;
  }
  .hljs .title,
  .hljs .bold,
  .hljs .strong,
  .hljs .tag,
  .hljs .section {
    font-weight: 600;
  }
  .hljs .link,
  .hljs .url {
    color: var(--color-primary);
  }
  .hljs .emphasis {
    font-style: italic;
  }
  .hljs .attr {
    font-weight: normal;
  }
  .hljs .attribute {
    color: #e6550d;
  }
`;

const focusedCSSBlock = css``;
const unfocusedCSSBlock = css`
  opacity: 0;
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
`;

export class CodeBlock extends React.Component {
  render() {
    const {
      showLineNumbers,
      disableStyles,
      language,
      truncateLength,
      isInEditor,
      isSelected,
      isFocused,
      data,
      ...otherProps
    } = this.props;

    if (isInEditor) {
      return (
        <div css={CodeBlockCSS}>
          <pre className="hljs">
            <code />
            <code>{this.props.children}</code>
          </pre>
        </div>
      );
    } else {
      return (
        <div css={CodeBlockCSS}>
          <SyntaxHighlighter
            {...otherProps}
            showLineNumbers={showLineNumbers}
            wrapLines
            useInlineStyles={false}
            language={undefined}
          >
            {this.props.text || ""}
          </SyntaxHighlighter>
          <div
            style={{ opacity: 0, pointerEvents: "none", position: "absolute" }}
          >
            {this.props.children}
          </div>
        </div>
      );
    }
  }
}

export default CodeBlock;
import * as React from "react"; import { css } from "@emotion/core"; import SyntaxHighlighter from "react-syntax-highlighter"; const CodeBlockCSS = css` position: relative; .hljs { direction: ltr; text-align: left; word-spacing: normal; word-break: normal; white-space: pre; overflow: auto; max-height: 500px; line-height: 1.2; tab-size: 2; padding: var(--offset-medium); background-color: var(--text-dark-color); color: var(--page-background); hyphens: none; border-radius: var(--border-radius); font-size: 16px; font-family: var(--monospace-font); -webkit-mask-image: radial-gradient( circle, var(--page-background) 100%, var(--text-dark-color) 100% ); -moz-mask-image: radial-gradient( circle, var(--page-background) 100%, var(--text-dark-color) 100% ); } @media (max-width: 500px) { .hls { max-height: 800px; } } .hljs::-webkit-scrollbar-track { background-color: #222; } .hljs::-webkit-scrollbar { height: 12px; width: 12px; opacity: 0.5; } .hljs::-webkit-scrollbar-thumb { background-color: var(--page-background); border: 3px solid #222; border-radius: 10px; } .hljs * { background: unset !important; } .hljs code:first-of-type { user-select: none; -webkit-user-select: none; } .hljs code + code { margin-left: var(--offset-medium); display: block; } .react-syntax-highlighter-line-number { color: #827d82; } /* ---- Syntax highlighting ---- */ .hljs .tag, .hljs .string, .hljs .meta, .hljs .symbol, .hljs .template-tag, .hljs .template-variable, .hljs .addition { color: #769fff; font-weight: normal; } .hljs .punctuation, .hljs .comment, .hljs .quote { color: #827d82; } .hljs .number, .hljs .regexp, .hljs .literal, .hljs .link { color: #31a354; } .hljs .deletion, .hljs .variable { color: #7e9eff; font-weight: normal; } .hljs .keyword, .hljs .operator { color: #ff6c6c; } .hljs .function { color: #d46dff; } .hljs .title, .hljs .bold, .hljs .strong, .hljs .tag, .hljs .section { font-weight: 600; } .hljs .link, .hljs .url { color: var(--color-primary); } .hljs .emphasis { font-style: italic; } .hljs .attr { font-weight: normal; } .hljs .attribute { color: #e6550d; } `; const focusedCSSBlock = css``; const unfocusedCSSBlock = css` opacity: 0; position: absolute; top: 0; bottom: 0; left: 0; right: 0; `; export class CodeBlock extends React.Component { render() { const { showLineNumbers, disableStyles, language, truncateLength, isInEditor, isSelected, isFocused, data, ...otherProps } = this.props; if (isInEditor) { return ( <div css={CodeBlockCSS}> <pre className="hljs"> <code /> <code>{this.props.children}</code> </pre> </div> ); } else { return ( <div css={CodeBlockCSS}> <SyntaxHighlighter {...otherProps} showLineNumbers={showLineNumbers} wrapLines useInlineStyles={false} language={undefined} > {this.props.text || ""} </SyntaxHighlighter> <div style={{ opacity: 0, pointerEvents: "none", position: "absolute" }} > {this.props.children} </div> </div> ); } } } export default CodeBlock;

What do you think? Codeblog isn't ready for everyone yet, but if you request access, I'll let you know when it's ready.

Edit (2019-02-22): This post is now hosted by codeblog.com.

Edit (2019-05-22): Some of this post is no longer true. Codeblog is not using MDX. This blog post is now written using Codeblog's Editor.