Want the Kalayani song to come alive on a tiny 0.96" SSD1306 OLED? This project plays a full 148-frame mono animation loop using Adafruit SSD1306 — perfect for desk toys, classroom demos, music-themed makers, and GIF-to-OLED experiments.
⬇ Free download — Kalayani OLED code
Full code.ino with all PROGMEM frames · ZIP or git clone
Parts list
- Board: ESP8266 NodeMCU / Wemos D1 Mini, ESP32, or Arduino Mega (recommended)
- Display: 0.96" SSD1306 I2C OLED, 128×64, usually
0x3C - 4 Dupont wires (VCC, GND, SDA, SCL)
- USB cable + Arduino IDE
Connection / wiring
Match your board. Wrong SDA/SCL is the #1 blank-screen cause.
| OLED pin | Arduino Uno / Nano | ESP8266 (NodeMCU) | ESP32 |
|---|---|---|---|
| VCC | 5V (or 3.3V if module requires) | 3.3V | 3.3V |
| GND | GND | GND | GND |
| SDA | A4 | D2 (GPIO4) | GPIO21 |
| SCL | A5 | D1 (GPIO5) | GPIO22 |
On ESP8266, call Wire.begin(4, 5) before display.begin() if default I2C pins fail.
If the screen stays black, try address 0x3D and read
OLED blank screen fixes.
Libraries
- Arduino IDE → Tools → Manage Libraries
- Install Adafruit SSD1306
- Install Adafruit GFX Library
- Select your board + correct COM port
How the player works
All frames are stored as const uint8_t PROGMEM frameN[1024]. In loop() the sketch
advances the index on a timer and draws the current bitmap:
void loop() {
static uint8_t frameIdx = 0;
static unsigned long lastMs = 0;
const uint8_t* frames[] = { frame0, frame1, /* ... */ frame147 };
const uint8_t numFrames = 148;
if (millis() - lastMs >= 318) {
lastMs = millis();
display.clearDisplay();
display.drawBitmap(0, 0, frames[frameIdx], 128, 64, SSD1306_WHITE);
display.display();
frameIdx = (frameIdx + 1) % numFrames;
}
}
Change 318 to speed up or slow down the song timing. Smaller = faster FPS
(example: 100 ≈ 10 fps).
Upload & run
- Open kalayanionoled → download ZIP or clone
- Open
code.inoin Arduino IDE - Install Adafruit GFX + SSD1306
- Pick ESP8266 / ESP32 / Mega + COM port
- Click Upload
- Watch Serial at 115200 — if you see
SSD1306 allocation failed, fix power/wiring/address
Ready to flash?
Get the complete Kalayani code.ino from GitHub now.
Make your own song animation
Kalayani was exported from oledanimationmaker.com:
- Open the free tool in Chrome/Edge
- Go to Import → drop a short GIF or video clip
- Tune FPS / frame count for your board flash
- Click Get the Code → Adafruit SSD1306 Arduino
- Paste into IDE (or push to your own GitHub)
Related guides: GIF to OLED, Image to byte array, SSD1306 animation basics.
Troubleshooting
- Sketch too big — use ESP8266/ESP32 or fewer frames
- Blank OLED — 3.3V on ESP, check SDA/SCL, try
0x3D - Slow / laggy — keep frame delay ≥ 50–80 ms; solid USB power
- Compile OOM — on ESP8266 set higher flash size in Tools
- Garbage at end of file — delete stray characters after the last
}incode.ino
FAQ
Is the Kalayani OLED code free?
Yes — github.com/itzmeAshish/kalayanionoled.
Does it play audio?
No — this is a visual OLED animation only. Pair a speaker separately if you need sound.
Can I change the song?
Yes. Import a different GIF/video into OLED Animation Maker and export a new sketch.
Build more OLED song & GIF animations
Pixel editor, GIF import, WebSerial live preview, Arduino & MicroPython export — free in the browser.
Open OLED Animation Maker →What code.ino holds for Kalayani
The GitHub repo itzmeAshish/kalayanionoled
is a single Adafruit sketch, code.ino. It is not a library and it does not
read a GIF at runtime. Everything the OLED will ever show is already compiled into the
file: 148 bitmaps named frame0 through frame147, each
const uint8_t PROGMEM and each exactly 1024 bytes. A pointer table lists
those arrays in order. setup() starts Serial at 115200, starts the SSD1306
at 0x3C, and loop() draws one bitmap every 318 ms.
Kalayani here is the picture loop only. The sketch has no audio pin, no MP3 decoder, and no lyric text. If you want the song itself, that is a separate player. This build is the 0.96" visual that goes with the title.
Arduino IDE wants the folder name to match the file. After you unzip, rename the folder
to code and then open code.ino. Leaving the folder named
kalayanionoled is a common reason the IDE asks to move the sketch or creates
a second copy. The file is not main.ino in this repo, so do not rename the
folder to main unless you also rename the file.
Kalayani timing table
The stock step is 318 ms, about 3.1 fps. One pass of all 148 frames is 148 × 318 ms ≈ 47 seconds. That slow step is why this loop still reads clearly on a 100 kHz I2C bus: pushing 1024 bytes takes on the order of 90 ms, and 318 ms leaves the transfer room to finish before the next index.
| Delay in loop() | Approx. fps | Full 148-frame pass | When to use it |
|---|---|---|---|
| 500 ms | 2 | ~74 s | A desk piece you glance at, not a music cue |
| 318 ms (stock) | ~3.1 | ~47 s | The timing shipped in code.ino |
| 200 ms | 5 | ~30 s | A bit snappier, still comfortable on default I2C |
| 100 ms | 10 | ~15 s | Busy motion; raise the I2C clock if frames skip |
Edit the number in the millis() test only. Leave numFrames at
148 unless you also delete bitmap arrays. Setting the count higher than the table reads
off the end of the pointer list and the panel fills with garbage. Setting it lower plays
a prefix of the loop and then jumps back to frame0, which is a fair way to
preview wiring before you trust the whole 47 second cycle.
Wiring when the comment still mentions Uno
The sketch comment lists Uno pins because that is the usual teaching default: SDA on A4,
SCL on A5, VCC on 5V. Many 0.96" modules accept 5V thanks to an onboard regulator,
and the address is 0x3C. Use those pins only if you have shortened the
animation. For this file as published, move to a board that can store it.
- ESP8266 NodeMCU: VCC to 3.3V, GND to GND, SDA to D2 (GPIO4), SCL to D1 (GPIO5). If the panel stays dark, add
Wire.begin(4, 5)beforedisplay.begin(). - ESP32: VCC to 3.3V, SDA to GPIO21, SCL to GPIO22. Do not use the Uno A4/A5 labels on an ESP32 DevKit. Those pins are not the I2C defaults.
- Arduino Mega 2560: the hardware I2C pins are still SDA 20 and SCL 21 (not A4/A5). Mega has 256 KB of flash, so the 148 KB of bitmaps can fit. The comment’s “A4/A5” line is the Uno map, not the Mega map.
Four dupont wires are enough. Keep them short. A 30 cm jumper pair on SDA and SCL is a frequent cause of a panel that works on the desk and dies when you move the project.
Why a classic Uno cannot play these 148 frames
Flash on the ATmega328P is about 32 KB, and the bootloader already keeps a slice of that. The bitmaps alone are 148 × 1024 = 151,552 bytes, roughly 148 KB, before Adafruit GFX, SSD1306, and Wire. That is several times the whole Uno. The IDE error is “sketch too big,” and no optimizer will squeeze a 148 KB table into 32 KB.
Nano (the classic one, not Nano ESP32 or Nano Every) has the same 32 KB ceiling. Mega
2560 can hold this particular sketch. An ESP32, or an ESP8266 module with 4MB of flash,
is the comfortable choice and matches the other long loops on this site. If you only own
an Uno, reopen the clip in OLED Animation Maker, cut the frame count into the low teens,
and export again. Do not delete random frameN arrays in the middle of
code.ino unless you also rebuild the pointer table. A hole in that list is
worse than a short loop.
Changing the 318 ms step
Find the comparison millis() - lastMs >= 318. Replace 318 with a value
from the table, upload again, and watch one full pass before you decide. The index wraps
with frameIdx = (frameIdx + 1) % numFrames, so the loop is endless. You do
not need a second timer for “end of song.” There is no audio to stay in sync with.
If you type a delay below about 80 ms, display() becomes the real clock.
The OLED will still advance, but the gap you typed is a minimum, not a promise. For
Kalayani’s stock 318 ms you will not hit that floor. Go slower (a larger delay) when
you are filming and want each picture to sit long enough for a phone to catch it.
A recording that shows the Kalayani loop honestly
Film the module, not the GitHub page. Fill the phone frame with the glass. Kill the ceiling light behind you so the cover glass does not mirror the room. OLED pixels are either lit or not. A wide shot of the whole bench makes 128 columns look like dust.
Record at least 50 seconds so one 47 second pass completes on camera. You should see the picture change, return to the opening frame, and continue. A take that stops at 10 seconds only proves the first handful of bitmaps. If the motion looks slower than the song you remember, that is the 318 ms step, not a dropped upload. This project does not play the track. A silent video of the panel is the correct result.
When upload succeeds and the panel does not
- Black screen: ESP boards must feed VCC from 3.3V. A 5V pin on a NodeMCU is not the logic supply for the display. Reseat SDA and SCL. On ESP8266, D2 and D1 are easy to swap because the silk is tiny.
- Wrong address:
SSD1306 allocation failedon Serial at 115200 usually meansbegin()did not see 0x3C. Change the address to0x3Dand upload once. If both fail, the chip is not on the bus. Check GND before you change libraries. - IDE board mismatch: a sketch compiled as “Arduino Uno” and sent to a NodeMCU will not run this file, and a sketch compiled as ESP32 will not run on an 8266. Pick the board that matches the USB chip, then pick the port that appears when you plug the cable in. Install the ESP8266 or ESP32 board package if the menu has no entry for your module.
- Not enough flash: on ESP8266 open Tools → Flash Size and choose the 4MB option that matches the module. A 512 KB or 1MB setting rejects a 148 KB bitmap table even when the chip is larger. The Uno error is the same problem with no menu that can fix it.
Kalayani bench questions
Does this sketch play the Kalayani audio?
No. code.ino is 148 monochrome frames on a 128×64 SSD1306. There is no speaker code. The title is the song name. The OLED plays the visual only.
I cloned kalayanionoled and the IDE complains about the sketch name. What folder do I use?
The file is code.ino, so the folder must be named code. It is not the main.ino layout used by some of the other song repos. Rename the folder, then open the file from inside it.
Can I keep the 148 frames and still use an Uno if I lower the fps?
No. The delay only changes timing. The bytes stay in flash. 148 KB does not fit in 32 KB at any frame rate. Use ESP32, a 4MB ESP8266, or a Mega, or export a much shorter frame list.
How do I know the 318 ms loop is actually running?
Time one pass with a watch. From the first picture back to the same picture should be about 47 seconds. A pass near 15 seconds means the delay was edited to 100 ms. A frozen first frame means the loop is not advancing, which points back at upload, power, or begin() failing before loop() draws.