[{"element_type":"text","content":"\n  \n  \n        \u003ch1\u003e\u003cstrong\u003eBuild the ¥enPocket 80 – A Retro Handheld Console from a VHS Tape!\u003c/strong\u003e\u003c/h1\u003e\n\u003cp\u003eHi, I'm Miguel (aka @miguel_drmr), a 16-year-old indie creator from Brazil, and I’m super excited to share my DIY console:\u003c/p\u003e\n\u003cp\u003eThe ¥enPocket 80 — a tiny retro-style handheld game console made from recycled VHS tapes, powered by an Arduino UNO, and super easy to build!\u003c/p\u003e\n\u003cp\u003eNo 3D printer? No soldering experience? No problem. Let’s bring retro vibes to life with just a few cheap parts and some creativity.\u003c/p\u003e\n\u003cp\u003e\u0026nbsp;\u003c/p\u003e\n\u003ch1\u003eWhat You’ll Need:\u003c/h1\u003e\n\u003cul\u003e\n\u003cli\u003e1x Arduino UNO (clone works!) The brain of the console\u003c/li\u003e\n\u003cli\u003e1x OLED Display 0.96\" (I2C) The tiny screen\u003c/li\u003e\n\u003cli\u003e1x Pushbutton To control the game\u003c/li\u003e\n\u003cli\u003eJumper wires (male-male) For wiring everything up\u003c/li\u003e\n\u003cli\u003e1x Old VHS tape (used) The console shell! Reuse \u0026amp; recycle!\u003c/li\u003e\n\u003cli\u003e1x Simple box (optional) To pack or transport\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch1\u003eWiring the Console:\u003c/h1\u003e\n\u003cp\u003e\u003cstrong\u003eLet’s wire it up!\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eOLED Display:\u003c/p\u003e\n\u003cp\u003eVCC → 5V\u003c/p\u003e\n\u003cp\u003eGND → GND\u003c/p\u003e\n\u003cp\u003eSCL → SCL\u003c/p\u003e\n\u003cp\u003eSDA → SDA\u003c/p\u003e\n\u003cp\u003e\u0026nbsp;\u003c/p\u003e\n\u003cp\u003ePushbutton:\u003c/p\u003e\n\u003cp\u003eOne leg → Digital Pin 2\u003c/p\u003e\n\u003cp\u003eOther leg → GND\u003c/p\u003e\n\u003cp\u003e(We’ll use INPUT_PULLUP in the code)\u003c/p\u003e\n\u003cp\u003e\u0026nbsp;\u003c/p\u003e\n\u003ch1\u003eStep 1: Prepare the Shell\u003c/h1\u003e\n\u003cp\u003eGrab your VHS tape and open it up (trust me, this part is fun). Remove the reels and internal gears carefully.\u003c/p\u003e\n\u003cp\u003eCut a hole where the screen will go — usually in the middle window of the tape.\u003c/p\u003e\n\u003cp\u003eAdd a small hole for the button, and maybe one more for the USB cable if needed.\u003c/p\u003e\n\u003cp\u003e\u0026nbsp;\u003c/p\u003e\n\u003ch1\u003eStep 2: Connect Everything\u003c/h1\u003e\n\u003cp\u003eUse jumper wires to hook up the display and the button to your Arduino.\u003c/p\u003e\n\u003cp\u003eYou can test the display using any basic I2C screen sketch.\u003c/p\u003e\n\u003cp\u003eOnce it’s working, fix the screen behind the VHS window using glue or tape. Do the same for the button.\u003c/p\u003e\n\u003cp\u003e\u0026nbsp;\u003c/p\u003e\n\u003ch1\u003eStep 3: Upload the Game\u003c/h1\u003e\n\u003cp\u003eUse the Arduino IDE to upload the built-in game. You can use a Dino Run clone, a reaction tester, or any 1-button game.\u003c/p\u003e\n\u003cp\u003eI’ll link my open-source version here: \u003ca href=\"https://github.com/smiluredev/YenPocket-80\"\u003e¥enPocket-Github\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003e\u0026nbsp;\u003c/p\u003e\n\u003ch1\u003eStep 4: Close It Up\u003c/h1\u003e\n\u003cp\u003eReassemble the tape and seal it — either with the original screws or with tape.\u003c/p\u003e\n\u003cp\u003eYou now have a fully working game console inside a VHS tape!\u003c/p\u003e\n      \n\n","metadata":{}},{"element_type":"user_image","content":"https://cdn-learn.adafruit.com/user_assets/assets/000/001/816/original/IMG-20250517-WA0046.jpg?1747685227","metadata":{}},{"element_type":"user_image","content":"https://cdn-learn.adafruit.com/user_assets/assets/000/001/817/original/IMG-20250518-WA0006.jpg?1747685252","metadata":{}},{"element_type":"user_image","content":"https://cdn-learn.adafruit.com/user_assets/assets/000/001/818/original/IMG-20250518-WA0012.jpg?1747685268","metadata":{}},{"element_type":"code","content":"#include \u003cWire.h\u003e\n#include \u003cAdafruit_GFX.h\u003e\n#include \u003cAdafruit_SSD1306.h\u003e\n\n#define SCREEN_WIDTH 128\n#define SCREEN_HEIGHT 32\n#define OLED_RESET    -1\n\nAdafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, \u0026Wire, OLED_RESET);\n\n#define BTN_PIN 2\n\n// Splash screen config\nunsigned long splashStart = 0;\nconst unsigned long splashDuration = 10000; // 10 segundos\n\n// Estados do sistema\nenum State {\n  SPLASH,\n  MENU,\n  GAME,\n  GAMEOVER\n};\n\nState currentState = SPLASH;\n\n// Dino Game config\nint playerX = 10;\nint playerY = 24; // chão\nint playerVY = 0;\nbool isJumping = false;\n\nunsigned long lastFrameTime = 0;\nconst unsigned long frameInterval = 50; // 20 FPS\n\nint obstacleX = SCREEN_WIDTH;\nconst int obstacleY = 24;\nconst int obstacleWidth = 8;\nconst int obstacleHeight = 8;\n\nbool gameOverFlag = false;\nint score = 0;\n\n// Para debouncing do botão\nbool lastButtonState = HIGH;\nbool buttonPressed = false;\nunsigned long lastDebounceTime = 0;\nconst unsigned long debounceDelay = 50;\n\nvoid setup() {\n  pinMode(BTN_PIN, INPUT_PULLUP);\n  Wire.begin();\n\n  if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {\n    while(1);\n  }\n\n  display.clearDisplay();\n  splashStart = millis();\n  lastFrameTime = millis();\n}\n\nvoid drawSplash() {\n  display.clearDisplay();\n  display.setTextSize(1);\n  display.setTextColor(SSD1306_WHITE);\n\n  const char *text = \"== YenPocket ==\";\n  int16_t x1, y1;\n  uint16_t w, h;\n  display.getTextBounds(text, 0, 0, \u0026x1, \u0026y1, \u0026w, \u0026h);\n  int16_t x = (SCREEN_WIDTH - w) / 2;\n  int16_t y = (SCREEN_HEIGHT - h) / 2;\n\n  display.setCursor(x, y);\n  display.println(text);\n  display.display();\n}\n\nvoid drawMenu() {\n  display.clearDisplay();\n  display.setTextSize(1);\n  display.setTextColor(SSD1306_WHITE);\n\n  display.setCursor(20, 12);\n  display.println(\"Press BTN to Start\");\n\n  display.display();\n}\n\nvoid startGame() {\n  playerX = 10;\n  playerY = 24;\n  playerVY = 0;\n  isJumping = false;\n\n  obstacleX = SCREEN_WIDTH;\n  score = 0;\n  gameOverFlag = false;\n\n  currentState = GAME;\n}\n\nvoid drawGame() {\n  display.clearDisplay();\n\n  // Chão\n  display.drawLine(0, 31, SCREEN_WIDTH, 31, SSD1306_WHITE);\n\n  // Player\n  display.fillRect(playerX, playerY - 8, 8, 8, SSD1306_WHITE);\n\n  // Obstáculo\n  display.fillRect(obstacleX, obstacleY - obstacleHeight, obstacleWidth, obstacleHeight, SSD1306_WHITE);\n\n  // Score\n  display.setTextSize(1);\n  display.setCursor(SCREEN_WIDTH - 40, 0);\n  display.print(\"Score: \");\n  display.print(score);\n\n  display.display();\n}\n\nvoid drawGameOver() {\n  display.clearDisplay();\n  display.setTextSize(1);\n  display.setTextColor(SSD1306_WHITE);\n\n  display.setCursor(20, 10);\n  display.println(\"GAME OVER!\");\n\n  display.setCursor(20, 20);\n  display.print(\"Score: \");\n  display.println(score);\n\n  display.setCursor(0, 30);\n  display.println(\"Press BTN to restart\");\n\n  display.display();\n}\n\n// Função para debouncing e leitura única do botão\nbool readButton() {\n  bool reading = digitalRead(BTN_PIN);\n\n  if (reading != lastButtonState) {\n    lastDebounceTime = millis();\n  }\n\n  if ((millis() - lastDebounceTime) \u003e debounceDelay) {\n    if (reading == LOW \u0026\u0026 !buttonPressed) {\n      buttonPressed = true;\n      lastButtonState = reading;\n      return true;\n    }\n    if (reading == HIGH) {\n      buttonPressed = false;\n    }\n  }\n  lastButtonState = reading;\n  return false;\n}\n\nvoid loop() {\n  unsigned long now = millis();\n\n  switch (currentState) {\n    case SPLASH:\n      drawSplash();\n      if (now - splashStart \u003e= splashDuration) {\n        currentState = MENU;\n      }\n      break;\n\n    case MENU:\n      drawMenu();\n      if (readButton()) {\n        startGame();\n      }\n      break;\n\n    case GAME:\n      if (now - lastFrameTime \u003c frameInterval) return;\n      lastFrameTime = now;\n\n      // Pulo\n      if (readButton() \u0026\u0026 !isJumping) {\n        isJumping = true;\n        playerVY = -6;\n      }\n\n      if (isJumping) {\n        playerY += playerVY;\n        playerVY += 1;\n        if (playerY \u003e= 24) { ẞ\n          playerY = 24;\n          playerVY = 0;\n          isJumping = false;\n        }\n      }\n\n      obstacleX -= 3;\n      if (obstacleX \u003c -obstacleWidth) {\n        obstacleX = SCREEN_WIDTH;\n        score++;\n      }\n\n      // Colisão\n      if (playerX + 8 \u003e obstacleX \u0026\u0026 playerX \u003c obstacleX + obstacleWidth) {\n        if (playerY \u003e= obstacleY - obstacleHeight) {\n          gameOverFlag = true;\n          currentState = GAMEOVER;\n        }\n      }\n\n      drawGame();\n      break;\n\n    case GAMEOVER:\n      drawGameOver();\n      if (readButton()) {\n        startGame();\n      }\n      break;\n  }\n}","metadata":{"language":"cpp","linenums":false}},{"element_type":"text","content":"\n        \u003ch1\u003eShare Your Games:\u003c/h1\u003e\n\u003cp\u003eYou can share your games made for your ¥enPocket 80 on my Official Forum:\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://drmrverse.boards.net/board/9/games-apps-softwares-websites\"\u003eDRMRVerse Forums\u003c/a\u003e\u003c/p\u003e\n      ","metadata":{}}]