Thanks to visit codestin.com
Credit goes to levels.io

, not inside the chart sections, so they need naming separately. */ .blogstats, .evchart, .folchart, .sentchart, .subchart, .tagwall, .vcfund, .fol-tip, .sc-tip, .svot-tip, .vcf-tip { font-variant-numeric: tabular-nums; } * { box-sizing: border-box; } html { background: var(--bg); } body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif; background: var(--bg); color: var(--fg); line-height: 1.65; margin: 0; } .theme-toggle { position: absolute; top: 1rem; right: 1rem; z-index: 10; background: none; border: none; cursor: pointer; font-size: 1.2rem; line-height: 1; padding: .35rem; color: var(--muted); opacity: .7; } .theme-toggle:hover { opacity: 1; } .subscribe-top { position: absolute; top: 1rem; right: 3.2rem; z-index: 10; background: var(--accent); color: #fff; font-size: .8rem; font-weight: 600; padding: .35em .85em; border-radius: 6px; border: 1px solid var(--accent); } /* Same hover treatment as .catch-emails-button: outlined ghost style. */ .subscribe-top:hover { background: none; color: var(--accent); text-decoration: none; } .wrap { max-width: 42rem; margin: 0 auto; padding: 3rem 1.25rem 5rem; } a { color: var(--accent); text-decoration: none; } a:hover { text-decoration: underline; } header.site { margin-bottom: 2.5rem; } header.site h1 { font-size: 1.4rem; margin: 0; } header.site h1 a { color: var(--fg); } header.site p { color: var(--muted); margin: .35rem 0 0; } .year { color: var(--heading); font-weight: 700; margin: 2.5rem 0 .75rem; font-size: 1.4em; } /* Date separator inside a post list — centred label with a hairline rule running out to each side. Used for both granularities (month when the list is dense, year when it isn't), so the two never look different. Distinct from .year, which is a section heading (Pinned, Related posts). */ .datesep { display: flex; align-items: center; gap: .75em; color: var(--muted); font-weight: 700; font-size: 1em; margin: 1.7rem 0 .6rem; } .datesep::before, .datesep::after { content: ""; flex: 1 1 0; height: 1px; background: var(--border); } .datesep a { color: inherit; text-decoration: none; } .datesep a:hover { color: var(--accent); text-decoration: underline; } .meta a { color: inherit; text-decoration: none; } .meta a:hover { color: var(--accent); text-decoration: underline; } .posts + .datesep { margin-top: 1.4rem; } ul.posts { list-style: none; padding: 0; margin: 0; } ul.posts li { display: flex; gap: 1rem; padding: .35rem 0; align-items: baseline; } ul.posts li time { color: var(--muted); font-variant-numeric: tabular-nums; font-size: .85rem; white-space: nowrap; flex: none; width: 4.6rem; } ul.posts li a { font-weight: 700; } ul.posts li .from-x { color: var(--muted); font-size: .85em; flex: none; margin-left: auto; } .draft-badge { font-size: .68em; font-weight: 700; text-transform: uppercase; letter-spacing: .04em; color: #b45309; background: #fef3c7; border-radius: 4px; padding: .1em .4em; flex: none; } html[data-theme="dark"] .draft-badge { color: #fcd34d; background: #3a2e0c; } .draft-notice { font-size: .9em; font-weight: 600; color: #b45309; background: #fef3c7; border-radius: 6px; padding: .4em .7em; margin: 0 0 1rem; display: inline-block; } html[data-theme="dark"] .draft-notice { color: #fcd34d; background: #3a2e0c; } /* "Covers" toggle: clickable thumbnail (or empty placeholder) after the date. */ ul.posts li .cover-link { flex: none; line-height: 0; } ul.posts li .cover-thumb { display: block; width: 72px; height: 48px; object-fit: cover; border-radius: 4px; background: var(--border); transition: opacity .15s; } ul.posts.covers li { align-items: center; } /* Cap listing titles at 2 lines so a long title never wraps to 3+ and leaves the date/thumbnail floating in the middle. Full title shows on hover + the post page. */ ul.posts.covers li a:not(.cover-link) { display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow: hidden; min-width: 0; } /* Thumb + title behave as one link: hovering either underlines the title and dims the thumb; clicking dims it further. */ ul.posts li:has(.cover-link:hover) a:not(.cover-link) { text-decoration: underline; } ul.posts li .cover-link:hover .cover-thumb, ul.posts li:has(a:not(.cover-link):hover) .cover-thumb { opacity: .75; } ul.posts li .cover-link:active .cover-thumb, ul.posts li:has(a:not(.cover-link):active) .cover-thumb { opacity: .5; } .sort-sep { margin-left: 1rem; } .notice { text-align: center; font-size: 1.3rem; font-weight: bold; line-height: 1.5; margin: 1rem 0 2.5rem; color: var(--heading); } .notice a { color: var(--accent); } article h1.title { font-size: 2rem; line-height: 1.2; margin: 0 0 .25rem; } article .meta { color: var(--muted); font-size: .9rem; margin-bottom: .75rem; } article .meta .meta-link { color: inherit; text-decoration: none; } article .meta .meta-link:hover { text-decoration: underline; } .post-tags { margin-bottom: 2rem; display: flex; flex-wrap: wrap; gap: .5rem; } .post-tags a { font-size: .8rem; font-weight: 600; color: var(--accent); border: 1px solid var(--border); border-radius: 999px; padding: .15rem .7rem; } .post-tags a:hover { text-decoration: none; background: var(--accent); color: #fff; border-color: var(--accent); } .tags-index { margin-top: 1.5rem; } .tags-index .tag-count { color: var(--muted); font-weight: 400; } .tags-index a:hover .tag-count { color: #fff; } article img, article video { max-width: 100%; height: auto; border-radius: 4px; display: block; margin: 1.75rem auto; } /* Ghost image figures: kill the browser's default 40px figure margin + center */ article figure.kg-image-card, article figure.kg-card-hascaption { margin: 1.75rem 0; text-align: center; } article figure.kg-image-card img, article figure.kg-card-hascaption img { margin: .5rem auto; } article figcaption { color: var(--muted); font-size: .85rem; margin-top: .4rem; text-align: center; } article img { background-color: var(--code-bg); background-image: linear-gradient(90deg, transparent, rgba(128,128,128,.12), transparent); background-size: 200% 100%; animation: img-shimmer 1.4s ease-in-out infinite; } article video { width: 100%; background: #000; } @keyframes img-shimmer { 0% { background-position: 200% 0; } 100% { background-position: -200% 0; } } figure.kg-embed-card { margin: 2rem 0; } figure.kg-embed-card iframe { max-width: 100%; } figure.kg-embed-card .twitter-tweet, figure.kg-embed-card .twitter-tweet-rendered { width: 100% !important; max-width: 100% !important; margin-left: auto; margin-right: auto; } figure.kg-embed-card .twitter-tweet-rendered iframe { width: 100% !important; max-width: 100% !important; } /* YouTube/Vimeo oembed iframes ship with fixed width/height attrs. Many old posts have them BARE (not wrapped in figure.kg-embed-card), so the generic `article iframe{height:auto}` rule below collapsed them to the 150px iframe default — the "weirdly short" players. Target both wrapped and bare embeds and give them a responsive 16:9 box. */ figure.kg-embed-card iframe[src*="youtube.com/embed"], figure.kg-embed-card iframe[src*="player.vimeo.com"], article iframe[src*="youtube.com/embed"], article iframe[src*="youtube-nocookie.com/embed"], article iframe[src*="player.vimeo.com"] { width: 100%; height: auto; aspect-ratio: 16/9; display: block; margin: 1.5rem auto; } figure.kg-bookmark-card { position: relative; display: flex; margin: 1.5rem 0; border: 1px solid var(--border); border-radius: 8px; overflow: hidden; min-height: 116px; } .kg-bookmark-container { position: absolute; inset: 0; z-index: 1; } .kg-bookmark-content { padding: 1rem 1.1rem; flex: 1 1 auto; min-width: 0; } .kg-bookmark-title { font-weight: 600; color: var(--fg); } .kg-bookmark-description { color: var(--muted); font-size: .9rem; margin-top: .4rem; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; } .kg-bookmark-metadata { margin-top: .6rem; font-size: .8rem; color: var(--muted); display: flex; align-items: center; gap: .5rem; } .kg-bookmark-icon { width: 18px; height: 18px; border-radius: 3px; background: none; animation: none; } .kg-bookmark-thumbnail { flex: 0 0 34%; max-width: 200px; } .kg-bookmark-thumbnail img { width: 100%; height: 100%; object-fit: cover; display: block; border-radius: 0; } @media (max-width: 480px) { .kg-bookmark-thumbnail { display: none; } } /* Internal "embed the post" card — replaces a tweet embed that's also a post here. */ figure.post-embed-card { display: flex; margin: 2rem 0; } .pec-link { display: flex; flex: 1; min-width: 0; text-decoration: none; overflow: hidden; border: 1px solid var(--border); border-radius: 8px; min-height: 96px; transition: border-color .1s; } .pec-link:hover { border-color: var(--accent); } .pec-content { padding: 1rem 1.1rem; flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; justify-content: center; } .pec-label { font-size: .72rem; text-transform: uppercase; letter-spacing: .04em; color: var(--muted); margin-bottom: .35rem; } .pec-title { font-weight: 600; color: var(--fg); line-height: 1.3; } .pec-thumb { flex: 0 0 34%; max-width: 200px; } .pec-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; } @media (max-width: 480px) { .pec-thumb { display: none; } } article h2 { margin-top: 2rem; } article pre { background:var(--code-bg); padding:1rem; overflow:auto; border-radius:6px; } article code { background:var(--code-bg); padding:.15em .35em; border-radius:3px; font-size:.9em; } article pre code { background:none; padding:0; } article blockquote { border-left:3px solid var(--border); margin:1.5rem 0; padding:.2rem 0 .2rem 1rem; color:var(--quote); } article table { border-collapse: collapse; width: 100%; margin: 1.5rem 0; font-size: .92em; display: block; overflow-x: auto; } article th, article td { text-align: left; padding: .5rem .7rem; border-bottom: 1px solid var(--border); white-space: nowrap; } article th { font-weight: 700; color: var(--heading); border-bottom: 2px solid var(--border); } article tbody tr:hover { background: var(--code-bg); } article tr.exited-row { background: #dcfce7; } article tr.exited-row:hover { background: #c7f0d6; } html[data-theme="dark"] article tr.exited-row { background: #14321f; } html[data-theme="dark"] article tr.exited-row:hover { background: #1b432a; } article blockquote > :first-child { margin-top:0; } article blockquote > :last-child { margin-bottom:0; } .backlink { display:inline-block; margin-bottom:2rem; color:var(--muted); } /* Post page top row: backlink left, edit button pushed to the right. */ .post-topbar { display:flex; justify-content:space-between; align-items:baseline; gap:1rem; } .post-topbar .backlink { margin-bottom:2rem; } .edit-link { color: var(--accent); font-size: .82em; white-space: nowrap; } ul.posts li .edit-link { flex: none; margin-left: auto; } ul.posts li .from-x ~ .edit-link { margin-left: .5rem; } footer.site { margin-top: 4rem; color: var(--muted); font-size: .85rem; } .site-search { margin: 0 0 1rem; } /* Same visual language as the newsletter email box: white field, blue ring, soft shadow (email box keeps its flat right edge for the button). */ .site-search input { width: 100%; padding: 19px; font-size: 15px; color: #3c484e; background: #fff; border: none; border-radius: 6px; outline: none; box-shadow: 0 0 0 1px var(--accent), 0 2px 4px 0 rgb(0 0 0 / 7%), 0 1px 1.5px 0 rgb(0 0 0 / 5%); } .site-search input:focus { box-shadow: 0 0 0 2px var(--accent), 0 2px 4px 0 rgb(0 0 0 / 7%); } /* Dark mode: dark field, quiet border (the white field + blue ring glared). */ html[data-theme="dark"] .site-search input { background: var(--bg); color: var(--fg); box-shadow: 0 0 0 1px var(--border); } html[data-theme="dark"] .site-search input:focus { box-shadow: 0 0 0 1px var(--accent); } .topnav { color: var(--muted); font-size: .85rem; margin: 0 0 1.6rem; } .search-sort { color: var(--muted); font-size: .85rem; margin-top: .5rem; } .search-sort-filter { margin-top: .15rem; } .search-sort strong { color: var(--fg); } ul.search-results { list-style: none; padding: 0; margin: 1.5rem 0 0; } ul.search-results li { margin: 0 0 1.5rem; } ul.search-results li a { font-weight: 700; } ul.search-results time { display: block; color: var(--muted); font-size: .8rem; margin-top: .15rem; } .snippet { color: var(--muted); margin: .3rem 0 0; font-size: .92rem; } .site-credit { margin-top: .8rem; font-size: .8em; color: var(--muted); } .post-source { margin-top: 2rem; color: var(--muted); } .post-ps { margin-top: 0; color: var(--fg); } hr { background-color: var(--hr); height: 1px; width: 100%; border-style: none; margin: 28px 0; } .post-nav { display: flex; justify-content: space-between; gap: 1.5rem; } .post-nav .prev, .post-nav .next { flex: 0 1 50%; } .post-nav .next { margin-left: auto; } .post-nav a { font-weight: 700; display: flex; align-items: center; gap: .4em; } .post-nav .next a { justify-content: flex-end; } .post-nav .chev { flex: none; font-size: 1.4em; color: inherit; line-height: 1; } .post-nav .t { text-align: center; } /* Pie chart of category breakdown (SVG with hoverable slices) */ .projects-pie-wrap { display: flex; justify-content: center; margin: 1.5rem 0; } .projects-pie { width: 380px; height: 290px; max-width: 100%; filter: drop-shadow(0 1px 4px rgba(0,0,0,.1)); } html[data-theme="dark"] .projects-pie { filter: drop-shadow(0 1px 6px rgba(0,0,0,.4)); } .projects-pie path, .projects-pie circle { cursor: default; transition: opacity 80ms; } .projects-pie path:hover, .projects-pie circle:hover { opacity: .85; } .pie-label { fill: var(--fg); font-size: 9px; font-weight: 600; dominant-baseline: central; pointer-events: none; } .pie-lead { stroke: var(--muted); stroke-width: 0.6; fill: none; } .chart-legend { display: flex; flex-wrap: wrap; gap: .5rem 1rem; margin-top: .8rem; font-size: .85em; color: var(--muted); } .chart-legend .legend-item { display: inline-flex; align-items: baseline; gap: .35rem; white-space: nowrap; } /* /ask-test chat UI */ .ask-form { display: flex; gap: .5rem; margin: 1rem 0 .5rem; } .ask-form input { flex: 1; padding: .6rem .8rem; font-size: 1rem; border: 1px solid var(--border); border-radius: 8px; background: var(--bg); color: var(--fg); font-family: inherit; } .ask-form input:focus { outline: 2px solid var(--accent); outline-offset: 1px; } .ask-form button { padding: .6rem 1.2rem; font-size: 1rem; font-weight: 700; background: var(--accent); color: #fff; border: none; border-radius: 8px; cursor: pointer; font-family: inherit; } .ask-form button:disabled { opacity: .5; cursor: wait; } .ask-suggest { font-size: .85em; color: var(--muted); margin-bottom: 1.2rem; } .ask-out { font-size: 1rem; line-height: 1.65; padding: 1rem 1.2rem; background: var(--code-bg); border-radius: 10px; min-height: 3rem; display: none; } .ask-out.show { display: block; } .ask-out.loading::before { content: 'Thinking'; color: var(--muted); font-style: italic; } .ask-out.loading::after { content: '...'; color: var(--muted); font-style: italic; display: inline-block; width: 0; overflow: hidden; vertical-align: bottom; animation: think-dots 1.4s steps(4, end) infinite; } @keyframes think-dots { to { width: 1.6em; } } .ask-out.error { background: rgba(239,68,68,.1); color: #b91c1c; } .ask-meta { font-size: .75em; color: var(--muted); margin-top: .6rem; padding-top: .6rem; border-top: 1px dashed var(--border); } /* Mobile: stop the page from gaining horizontal scroll, without forcing the .wrap container to 100% (which broke the centered 42rem desktop layout). iOS Safari sometimes ignores overflow-x on body alone — set it on html too. */ html, body { overflow-x: hidden; max-width: 100%; } /* Belt-and-suspenders: clamp every chart container to its parent so an oversized SVG / inline-styled bar can't push the page wider on mobile. */ .projects-pie-wrap, .projects-pie, .projects-chart, .chart-bar, .projects-timeline, .tl-bars, .tl-axis, .projects-scoreboard { max-width: 100%; box-sizing: border-box; } /* Long project names / pasted URLs in notes were also a culprit. */ .proj-name, .proj-note, .scorecard-names { word-break: break-word; overflow-wrap: anywhere; } article img, article video, article iframe { max-width: 100%; height: auto; } article pre, article code { max-width: 100%; overflow-x: auto; word-wrap: break-word; } /* Cursor-following tooltip for SVG charts (pie slices have no ::after). */ .chart-tooltip { position: absolute; background: rgba(20,22,26,.92); color: #fff; padding: 5px 10px; border-radius: 6px; font-size: 12px; line-height: 1.4; white-space: nowrap; pointer-events: none; opacity: 0; transition: opacity 60ms; z-index: 1000; font-weight: 500; } /* Bar-segment instant tooltip (HTML so ::after works, like the timeline tiles). */ .bar-seg { position: relative; } .bar-seg::after { content: attr(data-tip); position: absolute; bottom: 100%; left: 50%; transform: translateX(-50%) translateY(-6px); background: rgba(20,22,26,.92); color: #fff; padding: 5px 10px; border-radius: 6px; font-size: 12px; line-height: 1.4; white-space: nowrap; pointer-events: none; opacity: 0; transition: opacity 60ms; z-index: 5; font-weight: 500; } .bar-seg:hover::after { opacity: 1; } /* /projects scoreboard + list */ .projects-scoreboard { display: grid; grid-template-columns: repeat(2, 1fr); gap: 1rem; margin: 1.75rem 0 2.25rem; align-items: stretch; } .scorecard { padding: 1.2rem 1.2rem 1.1rem; border-radius: 12px; border: 1px solid rgba(0,0,0,.06); display: flex; flex-direction: column; } .scorecard.good { background: #dcfce7; } /* pastel green */ .scorecard.made { background: #fef3c7; } /* pastel yellow */ .scorecard.failed { background: #fee2e2; } /* pastel red */ .scorecard.nonprofit { background: #ede9fe; } /* pastel purple */ .scorecard.newproj { background: #dbeafe; } /* pastel blue */ .scorecard.exited { background: #fce7f3; } /* pastel pink (success-exit) */ /* If there's an odd number of cards, let the last one span both columns. */ .scorecard:last-child:nth-child(odd) { grid-column: 1 / -1; } html[data-theme="dark"] .scorecard { border-color: rgba(255,255,255,.06); } html[data-theme="dark"] .scorecard.good { background: #102b1f; } html[data-theme="dark"] .scorecard.made { background: #2b2616; } html[data-theme="dark"] .scorecard.failed { background: #2b1818; } html[data-theme="dark"] .scorecard.nonprofit { background: #1f1a2e; } html[data-theme="dark"] .scorecard.newproj { background: #11202e; } html[data-theme="dark"] .scorecard.exited { background: #2b1424; } .scorecard-head { font-size: .72em; color: rgba(0,0,0,.6); text-transform: uppercase; letter-spacing: .08em; font-weight: 700; } html[data-theme="dark"] .scorecard-head { color: rgba(255,255,255,.65); } .scorecard-count { font-size: 2.6em; font-weight: 800; line-height: 1; margin: .35rem 0 .15rem; color: rgba(0,0,0,.85); display: flex; align-items: baseline; gap: .4rem; } html[data-theme="dark"] .scorecard-count { color: rgba(255,255,255,.95); } .scorecard-pct { font-size: .42em; font-weight: 500; color: rgba(0,0,0,.5); letter-spacing: .02em; } html[data-theme="dark"] .scorecard-pct { color: rgba(255,255,255,.55); } .scorecard-names { margin-top: .9rem; padding-top: .9rem; border-top: 1px dashed rgba(0,0,0,.1); display: flex; flex-wrap: wrap; gap: .4rem; } html[data-theme="dark"] .scorecard-names { border-top-color: rgba(255,255,255,.1); } .name-pill { display: inline-block; padding: .22em .7em; border-radius: 999px; background: rgba(255,255,255,.75); color: rgba(0,0,0,.85); font-size: .82em; line-height: 1.5; border: 1px solid rgba(0,0,0,.06); text-decoration: none; font-weight: 500; transition: background 80ms, color 80ms, border-color 80ms; } html[data-theme="dark"] .name-pill { background: rgba(255,255,255,.08); color: rgba(255,255,255,.92); border-color: rgba(255,255,255,.06); } a.name-pill:hover { background: rgba(0,0,0,.85); color: #fff; border-color: transparent; text-decoration: none; } html[data-theme="dark"] a.name-pill:hover { background: rgba(255,255,255,.9); color: #15171a; } @media (max-width: 640px) { .projects-scoreboard { grid-template-columns: 1fr; } } .projects-list { margin-top: 1.5rem; } .proj-year { font-weight: 700; font-size: 1.25em; margin: 1.6em 0 .6em; } .proj-entry { display: flex; gap: .55rem; align-items: baseline; padding: .3rem 0; } .proj-date { color: var(--muted); font-variant-numeric: tabular-nums; width: 4.5em; flex: none; font-size: .9em; } .proj-name { font-weight: 700; } .proj-name a { color: var(--fg); } .proj-status { color: var(--muted); font-size: .82em; margin-left: auto; flex: none; } .proj-post { font-size: .9em; margin: -.15em 0 .6em 0; } .proj-post a { color: var(--accent); font-weight: 600; } .proj-note { color: var(--quote); font-size: .92em; margin: .15em 0 .5em 0; line-height: 1.55; } .cat-dot { font-size: 1.1em; line-height: 1; flex: none; } .cat-dot.good { color: #16a34a; } .cat-dot.made { color: #d97706; } .cat-dot.failed { color: #ef4444; } .cat-dot.nonprofit { color: #8b5cf6; } .cat-dot.newproj { color: #2563eb; } .cat-dot.exited { color: #ec4899; } /* 100%-stacked bar visualising the same breakdown */ .projects-chart { margin: 0 0 2rem; } .chart-bar { display: flex; height: 40px; border-radius: 8px; overflow: hidden; border: 1px solid rgba(0,0,0,.06); } html[data-theme="dark"] .chart-bar { border-color: rgba(255,255,255,.06); } .bar-seg { display: flex; align-items: center; justify-content: center; font-size: .82em; font-weight: 700; color: #fff; min-width: 2px; transition: opacity 80ms, transform 80ms; cursor: pointer; } .bar-seg:hover { opacity: .85; } .bar-seg.dim { opacity: .25; } .bar-seg.active { transform: scaleY(1.08); box-shadow: inset 0 0 0 2px rgba(255,255,255,.6); } /* Click-to-filter (multi-select): timeline gets `filtering` + a `sel-` class per chosen category; only those categories' tiles stay visible. Click a legend item or bar segment; shift-click to combine several. */ .projects-timeline.filtering .tl-seg { display: none; } .projects-timeline.filtering.sel-good .tl-seg.good { display: block; } .projects-timeline.filtering.sel-made .tl-seg.made { display: block; } .projects-timeline.filtering.sel-failed .tl-seg.failed { display: block; } .projects-timeline.filtering.sel-nonprofit .tl-seg.nonprofit { display: block; } .projects-timeline.filtering.sel-newproj .tl-seg.newproj { display: block; } .projects-timeline.filtering.sel-exited .tl-seg.exited { display: block; } .bar-seg.good { background: #16a34a; } .bar-seg.made { background: #d97706; } .bar-seg.failed { background: #ef4444; } .bar-seg.nonprofit { background: #8b5cf6; } .bar-seg.newproj { background: #2563eb; } .bar-seg.exited { background: #ec4899; } .chart-legend { display: flex; flex-wrap: wrap; gap: .5rem 1rem; margin-top: .8rem; font-size: .85em; color: var(--muted); } .legend-item { display: inline-flex; align-items: center; gap: .35rem; cursor: pointer; transition: opacity .1s; } .chart-legend.has-active .legend-item { opacity: .4; } .chart-legend.has-active .legend-item.active { opacity: 1; } .chart-legend .legend-item.active strong { text-decoration: underline; } .chart-hint { font-size: .8em; color: var(--muted); opacity: .7; margin: .5rem 0 0; } .legend-dot { display: inline-block; width: 10px; height: 10px; border-radius: 50%; box-shadow: inset 0 0 0 .5px rgba(0,0,0,.25); } .legend-dot.good { background: #16a34a; } .legend-dot.made { background: #d97706; } .legend-dot.failed { background: #ef4444; } .legend-dot.nonprofit { background: #8b5cf6; } .legend-dot.newproj { background: #2563eb; } .legend-dot.exited { background: #ec4899; } .legend-item strong { color: var(--fg); font-weight: 700; } /* Timeline (one column per year, stacked tiles per project) */ .projects-timeline { margin: 1.25rem 0 2rem; } .tl-controls { display: flex; gap: .8rem; align-items: center; margin: 0 0 .5rem; font-size: .85em; color: var(--muted); flex-wrap: wrap; } .tl-toggle { display: inline-flex; align-items: center; gap: .4em; cursor: pointer; user-select: none; } .tl-toggle input { cursor: pointer; margin: 0; } /* "Only show launches" hides every continuation tile (overrides filter rules too). */ .projects-timeline.launches-only .tl-seg:not(.tl-seg-launch) { display: none !important; } .tl-bars { display: flex; align-items: flex-end; gap: 1px; /* height set inline so PHP can scale to the busiest year */ border-bottom: 1px solid var(--border); padding: 0 0 1px; } .tl-col { flex: 1; display: flex; flex-direction: column-reverse; gap: 1px; min-width: 4px; height: 100%; justify-content: flex-start; } .tl-seg { flex: none; height: 4px; border-radius: 1px; display: block; position: relative; transition: filter 80ms; } /* Non-transforming hover so the child tooltip isn't stretched. */ .tl-seg:hover { filter: brightness(1.4) saturate(1.15); z-index: 2; box-shadow: 0 0 0 1px rgba(255,255,255,.4); } html[data-theme="dark"] .tl-seg:hover { box-shadow: 0 0 0 1px rgba(0,0,0,.4); } /* Instant tooltip on hover — native title has ~1s delay. */ .tl-seg::after { content: attr(data-tip); position: absolute; bottom: 100%; left: 50%; transform: translateX(-50%) translateY(-6px); background: rgba(20,22,26,.92); color: #fff; padding: 5px 10px; border-radius: 6px; font-size: 12px; line-height: 1.4; white-space: nowrap; pointer-events: none; opacity: 0; transition: opacity 60ms; z-index: 5; font-weight: 500; } .tl-seg:hover::after { opacity: 1; } .tl-seg.good { background: #16a34a; } .tl-seg.made { background: #d97706; } .tl-seg.failed { background: #ef4444; } .tl-seg.nonprofit { background: #8b5cf6; } .tl-seg.newproj { background: #2563eb; } .tl-seg.exited { background: #ec4899; } /* Revenue chart — same visual language as the timeline above it. */ .projects-revenue { margin: 1.25rem 0 2rem; } .rev-title { font-size: .85em; color: var(--muted); margin: 0 0 .5rem; } .rev-bars { display: flex; align-items: flex-end; gap: 1px; border-bottom: 1px solid var(--border); padding: 0 0 1px; } .rev-col { flex: 1; display: flex; flex-direction: column-reverse; gap: 0; min-width: 4px; height: 100%; justify-content: flex-start; } /* Faint inset outline keeps white/light segments (Merch, X) visible on light theme. */ .rev-seg { flex: none; display: block; border-radius: 1px; position: relative; transition: filter 80ms; box-shadow: inset 0 0 0 .5px rgba(0,0,0,.18); } html[data-theme="dark"] .rev-seg { box-shadow: inset 0 0 0 .5px rgba(255,255,255,.12); } .rev-seg:hover { filter: brightness(1.4) saturate(1.15); z-index: 2; box-shadow: 0 0 0 1px rgba(255,255,255,.4); } html[data-theme="dark"] .rev-seg:hover { box-shadow: 0 0 0 1px rgba(0,0,0,.4); } .rev-seg::after { content: attr(data-tip); position: absolute; bottom: 100%; left: 50%; transform: translateX(-50%) translateY(-6px); background: rgba(20,22,26,.92); color: #fff; padding: 5px 10px; border-radius: 6px; font-size: 12px; line-height: 1.4; white-space: nowrap; pointer-events: none; opacity: 0; transition: opacity 60ms; z-index: 5; font-weight: 500; } .rev-seg:hover::after { opacity: 1; } .tl-axis { display: flex; gap: 1px; font-size: .68em; color: var(--muted); margin-top: .4rem; } .tl-axis span { flex: 1; text-align: center; min-width: 4px; overflow: visible; white-space: nowrap; } /* When linked to from a pill, give the target row a subtle highlight + breathing room */ .proj-entry { scroll-margin-top: 1rem; transition: background 200ms; } .proj-entry:target { background: rgba(255,235,165,.35); border-radius: 6px; padding-left: .35rem; margin-left: -.35rem; } html[data-theme="dark"] .proj-entry:target { background: rgba(255,235,165,.08); } form.catch-emails { text-align: center; margin-top: 1.5rem; } /* Newsletter signup card on the front page, below the pinned box. */ .front-subscribe { margin: 1.5rem 0 0; padding: 1.25rem 1.25rem 1.5rem; border: 1px solid var(--border); border-radius: 8px; background: var(--code-bg); } /* Subscription-confirmed banner on top of the front page (/confirm). */ .confirm-banner { margin: 1rem 0 1.5rem; padding: 1rem 1.25rem; border: 2px solid var(--accent); border-radius: 8px; background: var(--code-bg); } .confirm-banner p { margin: .35em 0; } .front-subscribe p { margin: 0; text-align: center; color: var(--fg); } /* The lead line: inside the subscribe card on the blog, above it on the intro. */ .fs-lead { line-height: 1.45; text-wrap: balance; text-align: center; margin: 1.5rem 0 .75rem; color: var(--fg); } .fs-lead + .front-subscribe { margin-top: 0; } .front-subscribe .fs-note { max-width: 28rem; margin: .85rem auto 0; font-size: .8rem; color: var(--muted); line-height: 1.4; text-wrap: balance; } .front-subscribe form.catch-emails { margin-top: 1rem; margin-bottom: 0.5rem; } .catch-emails-text-box { outline:none; border:none; border-radius:6px; border-top-right-radius:0; border-bottom-right-radius:0; padding:12px; font-size:15px; vertical-align:middle; color:#3c484e; border-right:none; width:200px; box-shadow:0 0 0 1px var(--accent), 0 2px 4px 0 rgb(0 0 0 / 7%), 0 1px 1.5px 0 rgb(0 0 0 / 5%); } .catch-emails-button { cursor:pointer; background:var(--accent); appearance:none; color:#fff; padding:11px; font-weight:600; margin-left:0; font-size:15px; border-radius:6px; border-top-left-radius:0; border-bottom-left-radius:0; vertical-align:middle; border:1px solid var(--accent); z-index:1; position:relative; outline:1px solid var(--accent); width:130px; } .catch-emails-button:hover { background:none; color:var(--accent); border:1px solid var(--accent); } /* The intro keeps the chunkier 2px border it always had. */ #intro .catch-emails-button, #intro .catch-emails-button:hover { border-width:2px; } /* White on the accent measures 2.42:1 against the lighter dark-mode accent — well under the 4.5:1 AA wants for 15px/600 text. Dark text on the same blue is 7.41:1, so dark mode flips the label. */ html[data-theme="dark"] .catch-emails-button { color:#fff; } html[data-theme="dark"] .catch-emails-button:hover { color:var(--accent); } form.catch-emails .loading, form.catch-emails .error, form.catch-emails .success { display:none; } form.catch-emails.loading .not-subscribed, form.catch-emails.success .not-subscribed { display:none; } form.catch-emails.loading .loading { display:block; color:var(--muted); } form.catch-emails.error .error { display:block; color:#d33; margin-top:.5rem; } form.catch-emails.success .success { display:block; color:var(--accent); font-weight:600; } @media (max-width: 480px) { .catch-emails-text-box, .catch-emails-button { width:100%; margin:0 0 14px; display:block; border-radius:12px; } .catch-emails-button { margin:0; } } Subscribe
← all posts

List of all my projects ever

Updated 12 September, 2026 · 102,344 views

Here's a list of my sites, apps, side projects etc. I make a lot of stuff so it's fun to keep track. I'll try to keep it up-to-date from latest to oldest. I see this as kind of my resume. It also shows the incredibly high failure rate with any project I do. Most things I made never succeeded or made money.

Success 8%Okay 10%Failed 17%N/A 60%New 6%
9
11
19
69
7
Success: Made or still makes good money for a long time & grew 9Okay: Took off, Made money but not sustainable 11Failed: Did not take off and/or did not make money 19N/A: Non-profit or without profit goal 69New: Not sure yet because new project 7

Click to filter · shift-click to combine

19911995200020052010201520202026
Revenue per year (current year extrapolated)
19911995200020052010201520202026
Call center jobStudy grantPanda Mix ShowNomad ListRemote OKMAKE bookGoFuckingDoItRebasePhoto AIInterior AI𝕏 payoutsMerchpieter.comVibe JamInvestment returns
Exited: Exited and got acquired
00%
N/A: Non-profit or without profit goal
6960%
pieter.com Windows XP PCq1.pieter.comq2.pieter.comrtcw.pieter.comradio.pieter.compieter.orgpieter.netPieterOSq3.pieter.comResizeAPI.comNSFWapi.comGPUapi.neturl2og.comLoFi ATC BrazilLuggage Loserseu/accJSON.pubpieter.com Windows 3.11 PC@levelsio chat on Telegram@levelsio GPTMonkey Island AmsterdamPieter Levels: Startup AdventuresLego Box GeneratorAh Shit Here We Go AgainThe State of Remote WorkThe State of Digital NomadsRemote OK in Microsoft WordRemote OK in Google DocsRemote OK in VSCodeRemote WorkersMAKE Book NFT (sold)Inflation ChartColive.coAirline ListClimate FinderNomad List MeetupsBali Sea CableHow Much Is My Side Project WorthMaker RankNo More GoogleMake VillageFire CalculatorHow to Build a Startup Without FundingRemote Jobs APIMute LifeBootstrapping Side Projects Presentation3D and Virtual Reality DevEscape The BrexitKeep Your Fucking Resolutions1 Billion Digital Nomads PresentationHow Tech Is Shaping Our Future PresentationStartup RetreatsTaylor Bot3 months in San FranciscoReset your life#nomads12 Startups in 12 MonthsCall center sales job in NijmegenADVENTUR.BAT: Text Adventure Game in DOSMontessorischool Nijmegen Heyendaalseweg Elementary SchoolStedelijk Gymnasium Nijmegen High School (dropped out)Luzac College High SchoolPropedeuse in Business Administration at Hogeschool UtrechtBachelor of Science (BSc) in Business Administration at VU University AmsterdamExchange Program in Business Administration at Korea University Business SchoolMaster of Science (MSc) in Business Administration at Rotterdam School of Management Erasmus UniversityAggressive inline skatingSkateboardingQuake II Clan: Monsters of Confusion
2026
2026-08Infinite SlopActive
An endless AI-generated TV channel. Minimax H3 Max on fal.ai generates 10-second video clips faster than you can watch them, so I hooked it to a live stream where the chat decides what airs next — type anything and it becomes a video on TV. Surreal interdimensional-cable vibes, went viral with hundreds of people meme-bombing it live.
Read the story →
2026-07pieter.com Windows XP PCActive
I reverse engineered Windows XP to run it in your browser with classic programs like MSN Messenger, AIM and Winamp (with a lot of help from v86 by copy). Like a little time capsule to go back 20 years. Windows XP was the most legendary memorable OS ever I think, everyone remembers using it, it doesn't matter if you're 25 or 50.
2026-06q1.pieter.comActive
A web-based version of Quake I with a multiplayer server
2026-06q2.pieter.comActive
A web-based version of Quake II with a multiplayer server
2026-06rtcw.pieter.comActive
A web-based version of Return to Castle Wolfenstein with a multiplayer server
2026-06radio.pieter.comActive
A retro web radio station powered by Nullsoft SHOUTcast
2026-05levels.io blogActive
I vibecoded my own blog platform that also auto-pulls my posts on 𝕏 when I write there (because I use that as my blog platform these days), so finally I have all my content in one place. It also lets me do cool stuff like this projects page.
2026-04pieter.orgActive
A search engine that lets retro browsers surf the web
2026-04SuperLevelsActive
My first Chrome extension that is multi-functional and contains functions I used to have separate extensions for, but I made my own because it's safer and I don't trust Chrome extensions.
2026-04DroneSim.comActive
My entry to the Vibe Jam 2026 (although I can't win because I organize it), an FPV drone war simulator MMO vibe coded by me
2026-04PieterOSActive
DOS text-based user interface (TUI) running on the web called PieterOS
2026-04XDR BoostActive
A vibe-coded macOS app that lets you increase your MacBook Pro's screen brightness so you can work in the sun.
2026-03q3.pieter.comActive
A web-based version of Quake III with a multiplayer server powered by Q3JS by @lukathedev
2026-03Ericeira.comActive
2025
2025-12pieter.netActive
A dial-up ISP for retro computers I created with lots of help from @bai0. We emulated a virtual modem that dials into a phone number that is then routed over a WebSocket onto a PPP tunnel onto the internet and then back! You can use it on pieter.com/win31.
2025-07ResizeAPI.comActive
2025-07NSFWapi.comActive
2025-07GPUapi.netActive
2025-04url2og.comActive
2025-03Vibe JamActive
The first vibe coding game jam competition with sponsors like Cursor, Bolt, Lambda, CodeRabbit, Glif and Tripo
2025-03fly.pieter.com2025
2025-02LoFi ATC Brazil2025
2024
2024-10HotelistActive
I am so sick of booking sites that lie. They rank hotels based on how much money they make from them, and the EU forced them to admit this. If a hotel lowers their commission to the booking sites, they go up in the ranking. Also there are so many fake reviews now you can't trust booking sites or Google Maps. My goal with Hotelist is to fix this. I use AI to analyze hotels, browse the web to see what people say about them (not just on booking sites), and normalize ratings based on the actual range of booking site ratings (which is like everything is a 3.9 to 4.7 instead of 0 to 5!).
2024-06Luggage LosersActive
Vueling lost my gf's suitcase in June 2024 and it then went on a trip to random spots around the world without coming back to us, while we got gaslit by useless Vueling staff! We called and DM'd customer support, even messaged the CEO on LinkedIn, all without resolve. In the end we got it back because American Airlines found it. Not even Vueling.
2024-04eu/accActive
Movement to save Europe
2024JSON.pubActive
2024pieter.com Windows 3.11 PCActive
My crazy retro computer project to get a 1993 Windows 3.11 PC running in your browser with a dial-up internet connection. Read more about it on my blog: Building pieter.com, my retro PC in the browser
2024levelsio.com merchActive
2023
2023levels.vcActive
My angel investing in AI startups, plus some big-tech public stocks. Bets include Cursor (exited to SpaceX), Replicate (acquired by Cloudflare), Perplexity, fal, Sync and Blueprint.
2023Photo AIActive
2023@levelsio chat on TelegramActive
2023Profile ReviewActive
2023@levelsio GPT2023
2023Monkey Island Amsterdam2023
2023Pieter Levels: Startup Adventures2023
2023Lego Box Generator2023
2022
2022-09This House Does Not ExistActive
This project led to me creating Interior AI.
Read the story →
2022Ah Shit Here We Go AgainActive
2022Interior AIActive
Read the story →
2022Avatar AI2022-2023
Read the story →
2021
2021The State of Remote WorkActive
2021-11Rebase2021-2024
Rebase, immigration-as-a-service that lets you get legal and tax residency, and work permits in countries that want to attract high-tech remote workers. The first country it launched is Portugal.
2021-10The State of Digital NomadsActive
The State of Digital Nomads, an always-up-to-date research report on digital nomads and remote workers based on live data from tens of thousands of Nomad List members which makes it the biggest study on real digital nomads ever.
2021-09Remote OK in Microsoft Word2021
Remote OK in Microsoft Word, Google Docs and VSCode, I made different fake layouts so that people can browse remote jobs in the office without their boss finding out, it went very viral
2021-09Remote OK in Google Docs2021
2021-09Remote OK in VSCode2021
2021-08Remote WorkersActive
2021-03MAKE Book NFT (sold)2021
2021-02Inflation ChartActive
2020
2020-10QR Menu CreatorActive
QR Menu Creator, a site that lets restaurant owners create mobile friendly menus that customer can open by scanning a QR code on the table, to avoid Coronavirus; Product Hunt
2020-09IdeasAIActive
IdeasAI, an OpenAI-powered GPT-3 business idea generator which uses artificial intelligence to come up with new businesses; Product Hunt
2020-05Airline ListActive
Airline List, a comparison of airlines, airplane models and airports based on service quality and safety rankings
2020-01Climate Finder2020
Nomad List Climate Finder, pick a temperature and time period and find places that match based on your desired climate; Product Hunt
2020Nomad List Meetups2020
2019
2019-08Bali Sea Cable2019
Bali Sea Cable, monitors Bali's undersea internet cable performance; blog post
2019-01How Much Is My Side Project Worth2019
How Much Is My Side Project Worth?, a calculator to estimate how much your app, startup or side project is worth when you'd sell it; Product Hunt
2018
2018-12Maker Rank2018
Maker Rank, an index of Product Hunt makers ranked by upvotes; Product Hunt
2018-09No More Google2018
No More Google, privacy-friendly alternatives to Google that don't track you; Product Hunt
2018-04Make Village2018
MAKE Village, an MVP test to see if people would be interested in living together in a place, ~500 people showed interest; Results
2018-03Fire Calculator2018
Nomad List FIRE Calculator, a calculator to see where and when you can retire based on your current savings and income; Product Hunt
2018-03MAKE BookActive
MAKE Book, I wrote and self published a book on building startups without funding in public, it has sold 10,000+ copies; Product Hunt
2018-01How to Build a Startup Without Funding2018
How to Build a Startup Without Funding, I did a presentation at Dojo coworking space in Bali about bootstrapping startups. I think this is my favorite presentation I ever made as it quite clearly lays out the fundamentals of how I build my projects. It's essentially a summary of my book MAKE; blog post
2018Remote Jobs APIActive
2017
2017-08Nomad Gear2017
Nomad Gear, a crowdsourced index of the best gear for digital nomads; Product Hunt
2017-08Mute Life2017
2017-08HoodmapsActive
Hoodmaps, a crowdsourced map to navigate cities based on hipsters, tourists, rich, normies, suits and uni areas; Product Hunt, blog post
2017Ice Cream Chat2017
My attempt at a clone of Slack to use for Nomad List
2016
2016-07Colive.co2016-2017
A coliving platform for people to organize and find coliving and group travel dates for digital nomads
2016-09Bootstrapping Side Projects Presentation2016
2016-07Places to Work2016-2018
Places to Work, an app to find the best places to work near you
2016-053D and Virtual Reality Dev2016
2016Escape The Brexit2016
2016Keep Your Fucking Resolutions2016
2015
2015-101 Billion Digital Nomads Presentation2015
2015-07How Tech Is Shaping Our Future Presentation2015
2015-07Startup Retreats2015-2016
Startup Retreats, find remote work retreats for you and your startup
2015-07Taylor Bot2015-2016
Taylor Bot, a personal travel assistant bot on Telegram that tells you where to go and who is near you
2015-02Remote OK2026
Remote OK, a daily remote job aggregator which would pull jobs from other non-remote job boards if they were remote, this later merged with Nomad Jobs to become its own job board; Hacker News, Product Hunt, blog post
2014
2014-10#nomads2014-2016
#nomads, a Slack community for digital nomads, now part of Nomad List; Hacker News, Product Hunt, blog post
2014-10GIF Book2014-2015
GIF Book, make animated GIFs into paper flip books; blog post, Hacker News, Product Hunt
2014-08Nomad Jobs2014
Nomad Jobs, a remote job board for distributed/remote startups, and the precursor to Remote OK
2014-07Nomads.com (formerly Nomad List)Active
2014-05Tubelytics2013-2014
Tubelytics, a real-time analytics dashboard for YouTube creators and multi-channel networks
2014-04Go Fucking Do ItActive
Go Fucking Do It, set a goal and a deadline and if you don't reach your goal I charge your credit card; Hacker News, Product Hunt, blog post
2014-0312 Startups in 12 Months2014
12 Startups in 12 Months, to fight my depression and decreasing income, I decided to build one project per month for 12 months to see if I could get traction with anything
2014-03Play My Inbox2013
Play My Inbox, a site that pulls music links from YouTube and SoundCloud from your email inbox (which your friends would send you) and plays them in a nice interface
2013
2013-07@levelsio on 𝕏Active
My 𝕏 account that I have been posting on since 2013. I started it with very few people even seeing my posts for years, and mostly just used it for fun. It was the place my first project went kinda viral (which for me back then was like a few RTs): Nomad List. Then after that was the time of Product Hunt peaking around 2016-2018 and the start of the indie hacker scene, with lots of people starting to build in public like I was doing. Then around 2022 with the AI wave starting it became a very interesting place for me to ship my AI startups in public, as well as me talking more about society like the issues we have in Europe with degrowth and overregulation. And now 𝕏 also pays me, sometimes $16,000/month, so I'd say it's financially successful too.
2013-04Reset your life2013
I sold all my stuff, got a MacBook and a backpack and moved to Asia. I ended up staying for over a decade. The backstory is I was dating a Russian girl in December 2012 and even flew to Russia for her, and our plan was to move to Thailand in 2013. Every month she promised me she would book a flight but she didn't. So I flew in April myself and was expecting her to come too, but she wasn't there. So we kinda broke up and I was alone from then on the other side of the world!
2012
2012-013 months in San Francisco2012
On January 7 2012, I moved to San Francisco for 3 months with my friend Jim. He was writing his Master's Thesis in Cultural Anthropology about San Francisco's tech scene and specifically reciprocity — how investors and founders helped each other without immediately asking stuff back, but instead having some credit of reciprocity to help each other implicitly. I hopped on to write my Master's Thesis (unrelated to SF). We lived in cheap basements with gas leaks and a landlord who had a goose as a pet, and because we were so broke we couch-surfed for free, staying with 2 cool gay guys in Mountain View who worked for Akamai, and then ended up in a girl's house in the center of San Francisco where she worked for Square as a barista. Very crazy time and so many crazy stories! It was interesting to be so close to the SF startup scene which, now that I write this in 2026, seems early (2012), but back then already felt late! SF was a lot safer than it was later, a lot cleaner, and of course very progressive.
2012FML Dubstep2012
FML Dubstep was my try to pivot my Drum & Bass career into Dubstep, which became really big around 2011. We did make lots of cool music but it didn't take off.
2011
2011SparklesTV: How To Videos on YouTube2011
2011HotForYa: Missed Connections Dating Site for Uni Campuses2011
A missed connections dating site for university campuses on HotForYa.com, which I made with my friend Jim. The Dutch version was called Vind je leuk :) and this mockup shows it for Erasmus University Rotterdam.

HotForYa mockup, the Dutch version Vind je leuk :) for Erasmus University Rotterdam

2011Recording Hiphop and Making Music Videos2011-2013
2011-03SnapSnap: Cheap Taxis for the Netherlands2011
Me and my friend Robin Spiegel wrote a business plan for SnapSnap, a cheap-taxi app like Uber in the Netherlands, in March 2011, less than two years after Uber launched in 2009 as UberCab. We found rich famous entrepreneurs in the Netherlands who wanted to invest and pitched them for their investment fund. It turned out to be a massive time waste and they never invested in anyone and it was quite humiliating. It was a significant moment for me to stop being impressed by both venture capital investors and rich people who acted quite unfriendly and arrogant, and made me never wanna raise money or become that arrogant rich person also.

SnapSnap app mockups

SnapSnap taxi car mockup

2011Master of Science (MSc) in Business Administration at Rotterdam School of Management Erasmus University2011-2012
I wrote my master's thesis here: How technology changed the music industry, on what happened to artists after major record labels lost their century-old monopoly on production and distribution. I interviewed 12 artists, agents, labels and platforms. I started writing it during my 3 months in San Francisco in 2012. Download the PDF

Years later, in 2017, RSM's alumni magazine Outlook wrote about me and Nomad List:

The nomad lifestyler, RSM Outlook alumni magazine, Summer 2017

2010
2010-06Drum & Bass & Dubstep Merch2010
A Drum & Bass and Dubstep t-shirt and merch line I designed and sold through Spreadshirt.net, promoted via my Panda Mix Show channel. It sold pretty well and made $1,876 in total. This was on drumandbasstshirt.com, dubstepshirt.com, moombahtonshirt.com and emojishirt.com.
2009
2009-05AdSense Blog Network2009-2015
A network of AdSense blogs where I tried to make money with AdSense and Amazon affiliate links — I think at the peak they made $500/mo. AsusTablet.com was the most serious one, covering Asus's Eee T91 tablet, registered together with AsusT91.com/.net/.org/.info: I drove traffic to it with Google AdWords campaigns, outsourced blog posts via Mechanical Turk, and after a 6-year run sold it at auction on Flippa in 2015. AppleTablet.net was registered with MacBookTablet.com nine months before the iPad was announced, betting Apple's tablet would be called the Apple Tablet so I'd rank #1 on Google for it — Apple called it iPad, so that bet never paid off. And MyCancerDiet.com was a one-year experiment where I tried to publish correlations between cancer and diet, dead by 2010.
2009-09Exchange Program in Business Administration at Korea University Business School2009
An exchange program that changed my life. My first time outside Europe on the other side of the world. A complete cultural shock that changed the fundamentals of my identity forever and responsible for pretty much everything that came after — like my digital nomad journey for a decade and leaving my country forever. I blogged about it on hassepietersam.com.
2008
2008-09GrannyBike: Dutch Bikes in London2008
A business plan me and my brother Jeroen wrote for selling Dutch granny bikes (omafiets) in London. We downloaded a 29-page business plan template and we only ever filled in the cover page and one sentence. That's how far this one got.

Page from the GrannyBike business plan

2008Panda Mix Show2008-2014
I started uploading my music from my album Retake Manhattan below, including mixes. Back then in 2008 almost nobody uploaded music to YouTube — it was a site for videos after all! My videos started getting millions of views and I got invited by Google to join AdSense and was one of the first YouTubers in the Netherlands to make money with YouTube. It ranged from $1K/mo to $8K/mo at peak. I started getting requests by DJs to also upload their DJ mixes of their music, and I did. I always cleared all the music with the labels and it was all legal. After about 3 years the vibe changed when I started getting lots of copyright claims from labels and royalty agencies. The label ones were easy to clear — after all I had permission and would be asked by the labels themselves (!) to upload their music — but many labels would outsource to royalty agencies (like Merlin) and getting those copyright claims cleared was hard. It meant that slowly the labels would take all my money, and it didn't make sense to continue. I saw the end was near even though I was still making $5K/mo. I outsourced the video making to a friend and pretty much quit. In the meantime, while seeing my revenue drop every month, I had to find other income streams which is why I did 12 startups in 12 months in 2014.
2008Retake Manhattan2008
My first music album as PandaDNB, I pressed 1000 CDs and sold them online and the music was played on major radio stations like BBC Radio One
2008-09Bachelor of Science (BSc) in Business Administration at VU University Amsterdam2008-2011
I wrote my bachelor thesis here at the Amsterdam Center for Entrepreneurship: Firm Size & Innovation: The Advantages of a Small vs. Large Firm Size for Innovation. Public perception says big firms are slow and bureaucratic and small firms are agile and innovative — so if big firms are so bad at innovating, why do they still exist? I interviewed business leaders at both to find out. Download the PDF
2007
2007-09Propedeuse in Business Administration at Hogeschool Utrecht2007-2008
2006
2006One DNB Nijmegen: Night Club Event2006-2007
2005
2005Reaktor The Hague: Night Club Event2005-2007

Reaktor was a hard drum & bass night in The Hague that I organized with friends I knew from the Dutch drum & bass forum dnbforum.nl. It was my first real experience in entrepreneurship, with nights that drew 300 people. We booked the artists, organized the venue, sold tickets at the door, and promoted it with flyers we put up at universities and elsewhere.

Found footage from Reaktor IV on 13 June 2006.

2004
2004Call center sales job in Nijmegen2004
Outbound sales calls for Nationale Nederlanden, pitching their products to ING customers.
2004PandaDNB: Drum & Bass Producer and DJ2004-2008
I started making Drum & Bass music and posting it online. After lots of trying I finally started seeing my songs played by big DJs. Also they started getting playlisted by BBC Radio One (a very important radio station for Drum & Bass and electronic music). Back then I had just dropped out of my previous high school around age 16, lost most of my friends, was isolated, so doing music became my escape. Around 2005 it started taking off a bit, I started DJing in the Netherlands and UK, and started 2 Drum & Bass nights in The Hague in 2005 and my hometown Nijmegen in 2006. I learned a lot about organizing night club events and the economics of it. And that kinda made me really want to continue in entrepreneurship actually.
2003
2003Luzac College High School2003-2004
Luzac is essentially an expensive private school for kids that fucked up their high school, to finish it fast. I could do 2 years in 1, which since I had to re-do 3 years already in the previous high school meant I could make up for some time. It was expensive, about EUR 15,000, which I later paid back to my parents (in 2018).
1998
1998Stedelijk Gymnasium Nijmegen High School (dropped out)1998-2002
1998Skateboarding1998-1999
1997
1997Quake II Clan: Monsters of Confusion1997-1998
I joined a Quake II Clan and made the website for them too.
1995
1995Photoshop / Visual Arts / Design / Graffiti1995-2005
1994
1994ADVENTUR.BAT: Text Adventure Game in DOS1994
1994Aggressive inline skating1994-1996
I got pretty good at aggressive inline skating. I could grind frontal on a tube and grind sideways too. Then my oldest brother told me they'd stopped skating, so I quit too. Turned out he just didn't like that I was better than him — so he stopped inviting me along.
1991
1991Montessorischool Nijmegen Heyendaalseweg Elementary School1991-1998