From zero to production

MAKETEK

Build technology from scratch. No frameworks, no magic. Just raw code, step by step, from the most primitive form possible.

Learn the fundamentals that every developer should know before touching a framework.

0
Dependencies
Raw
Code Only
100%
Understanding

The Philosophy

Before you can break the rules, you need to know what the rules are. Before you use a framework, understand what it replaces.

Zero Abstraction

No frameworks hiding the logic from you. Every line of code does exactly what it says. You understand everything because you wrote everything.

Copy-Paste Ready

Every code block works as-is. Copy it, paste it, run it. No setup, no configuration, no "npm install" with 300 dependencies.

Primitive First

Start with the browser APIs. fetch() instead of Axios. querySelector() instead of jQuery. Understand what the tools do before using them.

Build to Learn

The goal is understanding, not shipping. Once you understand the primitives, frameworks become tools instead of magic boxes.

Step by Step

Each step builds on the previous one. By the end, you'll have a complete real-time application built with zero dependencies.

01

The Foundation: Pure HTML

Everything starts with HTML. No build tools, no bundlers. Just a text file that the browser can read. This is the skeleton of any website.

index.html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>My First Page</title>
</head>
<body>
  <h1>Hello, World</h1>
  <p>This is where everything begins.</p>
  <button id="btn">Click me</button>
</body>
</html>
Open this file directly in your browser. No server needed.
02

Styling: Raw CSS

CSS controls how things look. No Tailwind, no SASS. Write it by hand, understand every property. The cascade is your friend.

styles.css
/* styles.css */
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

body {
  font-family: system-ui, sans-serif;
  background: #0a0a0a;
  color: #e0e0e0;
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
}

h1 {
  font-size: 3rem;
  background: linear-gradient(135deg, #00f0ff, #7b61ff);
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
}

button {
  padding: 12px 24px;
  border: 1px solid rgba(255,255,255,0.1);
  border-radius: 8px;
  background: transparent;
  color: #fff;
  cursor: pointer;
  transition: all 0.3s;
}

button:hover {
  background: rgba(255,255,255,0.05);
  border-color: #00f0ff;
}
Link this in your HTML with <link rel="stylesheet" href="styles.css">
03

Logic: Vanilla JavaScript

JavaScript makes things interactive. No React, no Vue. Just plain JS manipulating the DOM directly. This is how it all works under the hood.

app.js
// app.js - Pure JavaScript, no dependencies

// Select elements
const btn = document.getElementById('btn');
const output = document.createElement('div');
document.body.appendChild(output);

// State - just a variable
let count = 0;

// Event listener
btn.addEventListener('click', () => {
  count++;
  render();
});

// Render function - manual DOM update
function render() {
  output.innerHTML = `
    <p>Clicked: ${count} times</p>
    <p>Last click: ${new Date().toLocaleTimeString()}</p>
  `;
  output.style.marginTop = '20px';
  output.style.color = count > 10 ? '#00ff88' : '#e0e0e0';
}

// Initial render
render();
console.log('App started - no framework needed');
Add <script src="app.js"></script> before </body>
04

Data: Fetch from an API

Real applications need data. The Fetch API is built into every browser. No Axios needed. Learn to talk to any server.

fetch-data.js
// Fetching data from a public API
async function loadData() {
  const container = document.getElementById('data');
  container.innerHTML = '<p>Loading...</p>';

  try {
    const response = await fetch(
      'https://api.coingecko.com/api/v3/simple/price?ids=solana&vs_currencies=usd'
    );
    const data = await response.json();

    container.innerHTML = `
      <div style="padding:20px; border:1px solid rgba(255,255,255,0.1); border-radius:12px;">
        <h3>Solana Price</h3>
        <p style="font-size:2rem; color:#00f0ff;">
          $${data.solana.usd.toLocaleString()}
        </p>
        <small style="color:#888;">
          Updated: ${new Date().toLocaleString()}
        </small>
      </div>
    `;
  } catch (error) {
    container.innerHTML = `<p style="color:#ff3366;">Error: ${error.message}</p>`;
  }
}

// Auto-refresh every 30 seconds
loadData();
setInterval(loadData, 30000);
This fetches real SOL price. Replace the URL with any API you want.
05

WebSocket: Real-Time Connection

HTTP is request-response. WebSocket is a persistent connection that receives data in real-time. This is how live feeds, chats, and trading bots work.

websocket.js
// Real-time WebSocket connection
const ws = new WebSocket('wss://pumpportal.fun/api/data');

ws.onopen = () => {
  console.log('Connected to PumpPortal');

  // Subscribe to new token launches
  ws.send(JSON.stringify({
    method: 'subscribeNewToken'
  }));
};

ws.onmessage = (event) => {
  const msg = JSON.parse(event.data);

  // New token created on PumpFun
  if (msg.txType === 'create') {
    console.log('NEW TOKEN:', {
      name: msg.name,
      symbol: msg.symbol,
      mint: msg.mint,
      creator: msg.traderPublicKey
    });

    // Add to page
    const div = document.createElement('div');
    div.textContent = `[${msg.symbol}] ${msg.name} - ${msg.mint.slice(0,8)}...`;
    document.getElementById('feed').prepend(div);
  }
};

ws.onclose = () => {
  console.log('Disconnected. Reconnecting in 3s...');
  setTimeout(() => location.reload(), 3000);
};
This connects to PumpFun and shows every new token launch in real-time.
06

Storage: Save Data Locally

Before you need a database, browsers have built-in storage. LocalStorage persists data between page reloads. Simple and effective.

storage.js
// Simple local storage wrapper
const Store = {
  get(key) {
    try {
      const data = localStorage.getItem(key);
      return data ? JSON.parse(data) : null;
    } catch {
      return null;
    }
  },

  set(key, value) {
    localStorage.setItem(key, JSON.stringify(value));
  },

  remove(key) {
    localStorage.removeItem(key);
  }
};

// Usage: Save user preferences
Store.set('theme', 'dark');
Store.set('watchlist', ['SOL', 'BTC', 'ETH']);
Store.set('settings', {
  notifications: true,
  autoRefresh: 30,
  currency: 'USD'
});

// Read it back
const watchlist = Store.get('watchlist');
console.log(watchlist); // ['SOL', 'BTC', 'ETH']

// This data survives page refresh and browser restart
localStorage has a 5MB limit. For more, use IndexedDB.
07

Component Pattern: Build UI Without Frameworks

React components? You can build the same pattern with vanilla JS. Create reusable pieces of UI that manage their own state.

components.js
// Vanilla JS component pattern
function TokenCard(token) {
  const el = document.createElement('div');
  el.className = 'token-card';
  el.innerHTML = `
    <div style="display:flex; gap:12px; padding:16px;
      background:#16161f; border:1px solid rgba(255,255,255,0.06);
      border-radius:12px; margin-bottom:8px;">
      <img src="https://pump.fun/coin/${token.mint}/image"
        width="40" height="40"
        style="border-radius:50%;"
        onerror="this.style.display='none'" />
      <div style="flex:1;">
        <strong>${token.name}</strong>
        <span style="color:#888; margin-left:8px;">$${token.symbol}</span>
        <div style="font-size:12px; color:#555; margin-top:4px;">
          ${token.mint.slice(0,8)}...${token.mint.slice(-4)}
        </div>
      </div>
      <a href="https://pump.fun/coin/${token.mint}"
        target="_blank"
        style="color:#00f0ff; font-size:13px;">
        View
      </a>
    </div>
  `;
  return el;
}

// Usage
const feed = document.getElementById('feed');
const token = { name: 'MyCoin', symbol: 'MC', mint: 'ABC123...' };
feed.appendChild(TokenCard(token));
This is essentially what React does under the hood, but without the virtual DOM.
08

Put It All Together

Combine everything into a single working application. HTML structure, CSS styling, JavaScript logic, API calls, WebSocket for real-time, and local storage. No npm install needed.

complete-app.html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>My PumpFun Feed</title>
  <style>
    * { margin:0; padding:0; box-sizing:border-box; }
    body { background:#050508; color:#f0f0f5; font-family:system-ui; padding:20px; }
    h1 { font-size:2rem; margin-bottom:20px; }
    #status { font-size:12px; color:#888; margin-bottom:16px; }
    .dot { width:8px; height:8px; border-radius:50%; display:inline-block; margin-right:6px; }
    .online { background:#00ff88; }
    .offline { background:#ff3366; }
    #feed { display:flex; flex-direction:column; gap:8px; }
  </style>
</head>
<body>
  <h1>PumpFun Live Feed</h1>
  <div id="status"><span class="dot offline"></span>Connecting...</div>
  <div id="feed"></div>

  <script>
    const feed = document.getElementById('feed');
    const status = document.getElementById('status');
    const ws = new WebSocket('wss://pumpportal.fun/api/data');

    ws.onopen = () => {
      status.innerHTML = '<span class="dot online"></span>Connected';
      ws.send(JSON.stringify({ method: 'subscribeNewToken' }));
    };

    ws.onmessage = (e) => {
      const msg = JSON.parse(e.data);
      if (msg.txType === 'create' && msg.mint) {
        const div = document.createElement('div');
        div.style.cssText = 'padding:12px; background:#16161f; border-radius:8px; border:1px solid rgba(255,255,255,0.06);';
        div.innerHTML = `<strong>${msg.name || '???'}</strong> <span style="color:#888;">$${msg.symbol || '???'}</span> <a href="https://pump.fun/coin/${msg.mint}" target="_blank" style="color:#00f0ff; float:right;">View</a>`;
        feed.prepend(div);
        if (feed.children.length > 50) feed.lastChild.remove();
      }
    };

    ws.onclose = () => {
      status.innerHTML = '<span class="dot offline"></span>Disconnected';
      setTimeout(() => location.reload(), 3000);
    };
  </script>
</body>
</html>
Save this as a single .html file and open it. That's it. A real-time PumpFun feed in ~40 lines.