Learn to code — from zero

Never written a line of code? Perfect. On this page you'll make a real light blink and a real buzzer play a tune, just by writing a few simple lines — no wiring, no setup, nothing to install. If you can write a shopping list, you can do this.

Start right now: open the Simulator in the IDE — it's a little pretend board inside your browser, with three coloured lights, a buzzer and a button. Everything here works there first, with no hardware at all.
Get started

What is a program?

A program is just a list of instructions a machine follows, one at a time, from top to bottom — like a recipe, or the steps of a dance. The machine is fast and very obedient: it does exactly what you wrote, in the order you wrote it. Nothing more, nothing less.

So "coding" is mostly about breaking what you imagine into small, clear steps. "Turn the red light on. Wait one second. Turn it off." That's already a program.

BASIC, and our Chip BASIC

BASIC is a programming language invented in 1964 to teach complete beginners — the name literally stands for "Beginner's All-purpose Symbolic Instruction Code". It reads almost like plain English, which is exactly why we use it here.

Our version is called Chip BASIC, and it's two things in one that you use together in the same program: the timeless BASIC core — line numbers, GOTO, IF…THEN, LET, variables and maths, the same ideas as BASIC since 1964 — plus our own commands that talk to the board: LED, WAIT, SOUND, PLAY, BUTTON and whole MISSIONs.

10 LET a = 0
20 LED green, on
30 WAIT 1s
40 LED green, off
50 a = a + 1
60 IF a < 3 THEN GOTO 20
70 MISSION "ALLARME"

One program, both layers at once: classic BASIC (LET, maths, IF…THEN, GOTO) runs the loop, and our commands (LED, WAIT, MISSION) make the board act. There's no mode to switch — you just mix them on whatever line you like.

Chip BASIC's golden rule: every line starts with a number (10, 20, 30…). Those numbers set the order the lines run in and give each line a name you can jump to. Count by tens, not 1-2-3, so you can slip new lines in between later — a line between 10 and 20 becomes 15.

How Text to Chip works

You write BASIC. The browser translates it into a list of tiny, simple instructions (we call it bytecode). A small "player" then runs those instructions — either in the Simulator on screen, or on a real chip (an ESP32-S3) connected by USB.

The clever part: it's the same translated program in both places. What you see blink in the simulator is what blinks on the real board. So you can build and test everything with no hardware, then run the exact same thing on a real chip later.

The big idea: you say what you want to happen — "red light on", "play a coin sound" — not how to wire a circuit. The board already knows how.

Your first program

Let's blink the red light. Open the IDE, make sure the Simulator is selected, and type these five lines into the editor:

10 LED red, on
20 WAIT 1s
30 LED red, off
40 WAIT 1s
50 GOTO 10

Now press ▶ run (top-left). The red light turns on for a second, off for a second, on again… forever. You just wrote a program! Press ■ stop to end it.

Here's what each line says:

  • 10 LED red, on — turn the red light on.
  • 20 WAIT 1swait 1 second (the light stays on while we wait).
  • 30 LED red, off — turn the red light off.
  • 40 WAIT 1s — wait another second (now it stays off).
  • 50 GOTO 10jump back to line 10 and do it all again. That's what makes it blink forever.
Try it: change 1s to 0.2s on both WAIT lines and run again — the light blinks much faster. Changing numbers and watching what happens is how you learn.

How the lines run

The player starts at the smallest line number and walks down: 10, then 20, then 30… If it reaches the end with nothing left, it stops.

GOTO changes that path: it jumps to whatever line you name. GOTO 10 sends the player back to line 10, which creates a loop — a piece that repeats. Loops are how a traffic light keeps cycling and a blink keeps blinking.

The language

The toolbox — every instruction

These are all the "words" Chip BASIC understands and turns into real action — the classic BASIC ones and our board commands side by side. Each card shows the shape of the instruction, what it does, and a tiny example. You don't need to memorise them — peek back here whenever you need one.

Lights, time & repeating

LED <colour>, <on|off>

Turns one of the three coloured lights on or off. Colours are red, yellow and green.

10 LED green, on
WAIT <n>s · WAIT <n>ms

Pauses the program. Use s for seconds or ms for milliseconds (1000 ms = 1 s). Decimals like 0.5s are fine. Whatever was on or off stays that way while it waits.

20 WAIT 2s
GOTO <line>

Jumps to another line number — the program carries on from there. Use it to loop, or to skip ahead.

50 GOTO 10
END

Stops the program cleanly. (A program that loops with GOTO never reaches an END — you stop it with the ■ button.)

90 END
REM <note>

A note to yourself. The machine ignores everything after REM, so use it to explain what a part does.

10 REM blink the light
<statement> : <statement>

Puts two instructions on the same line, separated by : — handy for short steps that belong together.

10 LED red, on : WAIT 1s

Making decisions

IF <condition> THEN <action>

Makes a decision: if the condition is true, then it does the action; otherwise it skips it. Conditions compare numbers with &gt;, &lt;, = and can join with AND.

30 IF a > 5 THEN LED red, on
BUTTON("A")

Is true while button A is being pressed. Put it inside an IF to react to a press.

30 IF BUTTON("A") THEN SOUND "coin"

Remembering numbers

LET <var> = <value> ( a … z )

Remembers a number under a name. You have 26 little boxes named a to z. LET is optional — a = 0 works too.

10 LET a = 0
+ - * / > < = AND ABS()

Do arithmetic with + - * /, compare with &gt; &lt; =, combine conditions with AND, and get a positive value with ABS(). Great for counting things.

20 a = a + 1

Making sound

SOUND "<name>"

Plays a sound on the buzzer: a short beep, or a named tune — mario, tada, coin, win, siren, scale.

40 SOUND "coin"
PLAY "<notes>"

Plays your own melody. Write notes as a letter + octave: c5, e5, g5. A - is a rest (silence), and :500 after a note sets its length in milliseconds.

50 PLAY "c5 e5 g5 c6"

Reusable blocks & whole missions

GOSUB <line> … RETURN

Jumps to a line like GOTO, but RETURN sends it back to where it came from. Use it for a block you want to reuse from several places (a "mini-program").

10 GOSUB 100
MISSION "<NAME>" [WITH k=v …]

Runs a whole ready-made behaviour in one line — a traffic light, a metronome, an alarm… Tune it with WITH name=value. More on this just below.

10 MISSION "SEMAFORO" WITH green=4s

Move, listen & see (robot + AI)

MOVE <left> <right>

Drives the two wheels: the first number is the left wheel, the second the right. Each speed is -255255 (minus = backwards, 0 = stop; ~160 is a good cruise — small motors stall below ~80). Different speeds steer: MOVE 40 160 curves left. It's sticky — the robot keeps going until the next MOVE, so stop with MOVE 0 0.

10 MOVE 160 160
SERVO <angle>

Turns a servo motor to an angle, from 0 to 180 degrees.

20 SERVO 90
VOICE()

The last word the robot heard with its microphone (the AI). Use it inside an IF. Words it knows: go, left, right, stop.

10 IF VOICE()="go" THEN MOVE 160 160
SEE()

What the robot's camera recognizes (the AI). Use it inside an IF. Things it knows: person, ball, hand.

10 IF SEE()="person" THEN SOUND "coin"
SENSOR("<name>") · AREAD()

Reads an analog sensor — a number from 0 to 4095, like a distance or a light level. Use it inside an IF to react when it's small or large.

10 IF SENSOR("radar") < 20 THEN MISSION "ALLARME"

Ready-made missions

A mission is a complete behaviour someone already built for you. Instead of writing the whole traffic-light dance line by line, you call it in one line:

10 MISSION "SEMAFORO" WITH green=4s yellow=1s red=4s beep=slow
20 GOTO 10

The WITH part tweaks it: how long green lasts, the beep speed, and so on. Each mission allows certain settings within safe limits (a traffic light won't let you switch red off — that would be unsafe). The available ones are in the Library in the sidebar: SEMAFORO (traffic light), PIANOLA (keyboard), METRONOMO (beat) and ALLARME (alarm).

Easiest way to change a mission's settings: click the MISSION line in the editor — a little form opens with every option, ready to adjust.

The mission catalog

Here's every mission you can run in the simulator today, by tier. Open any one from the Library (the grid in the sidebar) — or just write its line, e.g. MISSION "RADAR". Each one can be tuned with WITH, just like the traffic light above.

Junior

  • MISSION "SEMAFORO" Traffic light · RGB cycle
  • MISSION "METRONOMO" Metronome · BPM beat
  • MISSION "ALLARME" Alarm · Beep trigger
  • MISSION "TIMER" Timer · Countdown
  • MISSION "CONTAPASSI" Step counter · IMU

Maker

  • MISSION "MOVIMENTO" Motion · PIR sensor
  • MISSION "TERMOMETRO" Thermometer · Temp threshold
  • MISSION "NOTTURNA" Night light · Light sensor
  • MISSION "BARRIERA" Barrier · Servo gate
  • MISSION "POMPA" Pump / timer · scheduled relay
  • MISSION "HIGHWAY" Highway Road · Avoid obstacles
  • MISSION "LINEFOLLOW" Line Follower · Follow a line

Pro · AI

  • MISSION "ROBOCAR" Voice car · autonomous · 3 wheels
  • MISSION "VOICE" Voice · edge-AI · commands
  • MISSION "TROVAPALLA" Find the ball · Camera hunt

It's parameterizable. Add a WITH clause to adjust the timings, the beep and the button:

MISSION "SEMAFORO" WITH green=6s yellow=1s red=4s beep=off|slow|fast button=on|off minGreen=2s

Ranges: green 2–15s, yellow 0.5–3s, red 2–15s, minGreen 2–10s. beep is off, slow or fast; button is on or off. Durations accept decimals or milliseconds (0.5s, 1500ms). Set just the parameters you care about, e.g. MISSION "SEMAFORO" WITH green=4s beep=fast.

The pedestrian button

When button=on, pressing the button is a crossing request: the green LED blinks immediately to acknowledge it, then the light turns to red as soon as green has lasted at least minGreen (so a press can't stop traffic instantly). On the simulator, click the on-screen button; on hardware, wire it to GPIO 6 (active-low, to GND).

Fixed safety guardrails

Some things can't change — they're safety guardrails: the lights always cycle green → yellow → red, one light at a time, the walk beep sounds only on red, and a button press can never cut green below minGreen.

Let the assistant help (the @ helper)

Stuck, or in a hurry? At the bottom of the editor there's an @ describe a change box. Type what you want in plain words — "make the light blink faster" or "play a happy tune when I press the button" — and the assistant writes or edits the BASIC for you.

It always answers in real BASIC lines, right in the editor — so you can read them, run them, and learn from them. The assistant is a teacher that shows its work, not a black box.

Tip: it replies in your chosen language. Switch the language in the header and the explanations follow.

Auto-run

There's an Auto-run toggle in the topbar, on by default. When the program changes and compiles cleanly, it's loaded and run automatically on the active backend — so you see the result live without clicking Upload & Run yourself.

A few complete programs

Paste any of these into the editor and press run. Then change a number and see what happens — that's the whole game.

A traffic light

10 LED red, on
20 WAIT 5s
30 LED red, off
40 LED yellow, on
50 WAIT 1s
60 LED yellow, off
70 LED green, on
80 WAIT 5s
90 LED green, off
100 GOTO 10

Red for 5 seconds, yellow for 1, green for 5, then GOTO 10 starts the cycle over. Try changing the wait times.

Press the button → coin sound

10 IF BUTTON("A") THEN SOUND "coin"
20 GOTO 10

Line 10 checks the button over and over (line 20 loops straight back to it). Hold button A in the simulator and you'll hear the coin tune.

Play a little melody

10 PLAY "c5 e5 g5 c6"
20 END

Four notes going up, then it ends. Change the notes — try "c5 d5 e5 f5 g5" — and run it again.

Going further

Those building blocks look small, but they combine into anything — a handful of commands plus a little logic is all a real program is. Here are the patterns that take you from "blink a light" to something that thinks.

Repeat an exact number of times

10 LET a = 0
20 LED red, on
30 WAIT 0.3s
40 LED red, off
50 WAIT 0.3s
60 a = a + 1
70 IF a < 5 THEN GOTO 20
80 SOUND "tada"
90 END

A variable is a little box that remembers a number. Here a counts the blinks: line 60 adds one each loop, and line 70 keeps jumping back until a reaches 5 — then a fanfare. Change the 5 to repeat as often as you like.

Reuse a block — GOSUB and RETURN

10 GOSUB 100
20 WAIT 1s
30 GOSUB 100
40 END
100 SOUND "coin"
110 LED green, on
120 WAIT 0.5s
130 LED green, off
140 RETURN

Write a block once, use it everywhere. GOSUB 100 jumps to line 100; RETURN sends control back to right after the call. Lines 100–140 are a "beep + flash" block the main program runs twice. Big programs are built from small reusable blocks exactly like this.

Remember a state

10 LET a = 0
20 IF a = 0 THEN LED red, on
30 IF a = 1 THEN LED green, on
40 WAIT 0.5s
50 LED red, off
60 LED green, off
70 a = 1 - a
80 GOTO 20

A variable can hold which step you're on, not just a count. Here a is whose turn it is — red (0) or green (1) — and a = 1 - a flips it between 0 and 1 every loop, so the lights alternate. That tiny memory is how a program decides over time.

Maths and combined conditions

10 LET a = 10
20 LET b = 3
30 IF a > 5 AND b < 5 THEN SOUND "coin"
40 LET a = a - b
50 IF a = 7 THEN LED green, on
60 END

You can do arithmetic anywhere a number goes, and join tests with AND. Line 30 fires only if both conditions are true; line 40 updates a with a subtraction. With + - * /, &gt; &lt; =, AND and ABS() you can express real rules.

A robot is a sequence of missions

10 MISSION "SEMAFORO" WITH green=2s yellow=1s red=2s
20 MISSION "METRONOMO" WITH beat=0.4s bar=4
30 GOTO 10

The biggest idea: a whole project is just missions in a row, steered by the BASIC you've learned. Each line here is a complete behaviour; GOTO 10 loops the show. Swap the missions, add an IF to choose between them, count rounds with a variable — and you're programming a robot.

Now mix them: blink a light five times and then run a mission; count button presses and play a different tune every third one; alternate two missions each loop. Every one of those is just the patterns above, combined — that's all programming really is.
On the board

Where your program runs

Browser requirement for real hardware: Web Serial works only in a Chromium desktop browser (Chrome, Edge, Brave) over HTTPS — which https://textochip.com provides. Firefox/Safari and mobile can still use the Simulator.
Simulator
No hardware

Runs entirely in the browser. Works for everyone, any OS. Best place to start.

ESP32-S3
Verified hardware

The reference board. Flash the Zephyr firmware once, then upload & run over USB.

More boards
One toolchain

The firmware is Zephyr, so the same code targets new chips — only a tiny HAL file changes. Nordic nRF54L next.

The workflow (same for every backend)

  1. Type @ and your request on a line in the editor (the AI writes the BASIC), or pick a ready program from the Library in the sidebar. The program is numbered BASIC you edit directly.
  2. Choose where it runs with the Simulator / Real board toggle.
  3. Compile — the console shows the result (instruction count and any warnings).
  4. Upload & Run — sends the program and starts the VM (with Auto-run on, this happens after every change).
  5. Stop halts it; type an OVERRIDE: command on a line (e.g. OVERRIDE: STOP or OVERRIDE: SET 4 0) and press Enter to inject one instruction live, without re-uploading.

Make it run on its own (Save to board)

On a real board, press Save to board to store the program in the board's flash and run it on every boot. Now you can unplug the PC: power the board from any USB charger or battery and it runs on its own — press RST to restart it. The program stays until you save a new one or press Autorun off. This is the whole point: you build the behaviour in the browser, then the chip keeps doing it with no computer attached.

1 · Simulator (no hardware)

  1. Open https://textochip.com in any browser.
  2. Leave the toggle on Simulator (it auto-connects).
  3. Click Upload & Run. The on-screen LEDs, buzzer indicator and button mirror exactly what a real board would do.
  4. For programs that read the button, click the on-screen button to drive the input pin.

The simulator is a TypeScript VM with the same instruction set and tick model as the firmware, so a program that works here behaves identically on the board.

2 · ESP32-S3 (recommended, verified)

Reference board: Freenove ESP32-S3-WROOM (USB-C, two USB ports). You flash the generic Zephyr VM firmware once; after that you upload bytecode from the IDE as many times as you like — no re-flashing to change the program.

Get the firmware

The board runs a small generic VM firmware built with Zephyr. It lives in its own open repo, textochip-runtime; you build and flash it once from there, then upload programs from the browser. The full, copy-pasteable steps live in that repo's README.

What you need

  • ESP32-S3 board + USB-C cable (the Freenove exposes two USB ports — both are used)
  • Breadboard, 3 LEDs (red/yellow/green) + ~220–330 Ω resistors
  • A passive piezo buzzer and a push button (optional)
  • The Zephyr toolchain: a west workspace + the Zephyr SDK (see the Zephyr Getting Started guide)

Wiring

ComponentPinWiring
Green LEDGPIO 1→ resistor → GND
Yellow LEDGPIO 2→ resistor → GND
Red LEDGPIO 4→ resistor → GND
Buzzer (passive)GPIO 5→ GND
Button AGPIO 6→ GND (internal pull-up; active-low)

These pins come from the board profile (lib/boardProfile.ts); the compiler bakes them into the bytecode. GPIO 1/2/4/5/6 are safe digital I/O on the ESP32-S3.

Build & flash the firmware (one time)

  1. Set up the Zephyr toolchain — a west workspace and the Zephyr SDK (Zephyr's Getting Started guide). The firmware sources are in their own repo, textochip-runtime (clone it).
  2. From the textochip-runtime clone, build for the ESP32-S3:
    west build -b esp32s3_devkitc/esp32s3/procpu zephyr
    Run west packages pip --install once so esptool ≥ 5.0.2 is on your PATH at flash time.
  3. Plug in the board's “USB UART” port (the CH343 chip) and flash with west flash — esptool's auto-reset into download mode works on this port.
  4. If a flash can't auto-reset (e.g. the firmware is already running): hold BOOT, tap RST, release BOOT, then west flash again.
  5. Two ports, two jobs: you flash over the “USB UART” port, but you connect the IDE over the “USB OTG” (native-USB) port — do not swap them.

Connect & run from the IDE

  1. Open https://textochip.com in Chrome/Edge/Brave.
  2. Switch the toggle to Real board.
  3. Click Connect board and pick the board's “USB OTG” (native-USB) port — it shows as CDC_ACM_serial_backend. (Not the “USB UART” port you flashed from.)
  4. Click Upload & Run. Use Stop and Override at runtime.
Pick the right port. The IDE connects over the “USB OTG” native-USB port — an app-provided CDC-ACM that does not reset on connect. The “USB UART” port is only for west flash; opening it in the browser would reset the chip (you'd see WARN: no PONG).

3 · Other boards (Zephyr)

Because the firmware is Zephyr, the very same VM, ISA and missions run on any board Zephyr supports — only a tiny HAL file changes. The browser compiler, the serial protocol and your .bas programs stay identical, so the whole IDE flow is unchanged from board to board.

What changes per board

Two things only: the GPIO numbers in lib/boardProfile.ts (the compiler bakes them into the bytecode), and one HAL implementation — about 9 functions mapping pins/PWM/clock to that chip. Then build for the target with west build -b &lt;board&gt; zephyr.

Nordic nRF54L (incoming)

The next target is the nRF54LM20 DK. Build it with the nRF Connect SDK (Nordic's Zephyr): west build -b nrf54lm20dk/nrf54lm20a/cpuapp zephyr, then west flash. Same IDE flow over Web Serial; BLE OVERRIDE and edge-AI missions on the Axon NPU come next.

Help & reference

The language, briefly

A first program — a looping traffic light (Project 01):

10 LED red, on
20 WAIT 5s
30 LED red, off
40 LED yellow, on
50 WAIT 1s
60 LED yellow, off
70 LED green, on
80 WAIT 5s
90 LED green, off
100 GOTO 10

The executable subset compiles to bytecode: LED, WAIT, GOTO, GOSUB/RETURN, IF … THEN, LET, arithmetic and comparisons (&gt;= &lt;= &lt;&gt; included), SOUND/PLAY (beeps & melodies), BUTTON("A"), the robot + edge-AI commands MOVE, SERVO, VOICE(), SEE() (objects and colours like "yellow") with SEEX() (where it is in the frame, 0-100) and SEESIZE() (how big it looks, 0-100: bigger means closer), DISTANCE() (centimetres) and SENSOR()/AREAD(), and MISSION blocks (e.g. a complete pedestrian crossing). Statements that need hardware this board doesn't have (GPS, a display…) still compile — they emit a no-op and a console warning instead of failing.

Tips & common mistakes

  • Every line needs a number. A line without one (just LED red, on) won't run — write 10 LED red, on.
  • Count by tens (10, 20, 30) so you can slip a new line in between later.
  • Times need a unit: WAIT 2s (seconds) or WAIT 500ms (milliseconds). A bare WAIT 2 means 2 milliseconds — almost nothing!
  • A GOTO loop never stops on its own. That's usually what you want (a blinking light) — press the ■ stop button to end it.
  • The console talks to you. If something's wrong, the console under the editor shows a yellow warning or a red error with the line number. Read it — it's trying to help.
  • Small steps win. Run often. Change one thing, run, look. You learn far more from ten tiny experiments than one big guess.

Troubleshooting

  • No “Connect board” button / it does nothing: you're not on a Chromium desktop browser, or not on HTTPS. Use Chrome/Edge/Brave on https://textochip.com.
  • “no PONG” on connect: you probably opened the “USB UART” port (which resets the chip). Pick the “USB OTG” port (CDC_ACM_serial_backend) instead; if it still fails, press RST, wait ~3 s, reconnect.
  • Port missing on Linux: add yourself to dialout (sudo usermod -a -G dialout $USER) and log out/in.
  • Nothing lights up: check the LED polarity and that the wired pins match the board profile.