diff --git a/Makefile b/Makefile
index f50b7622..124c7ec6 100644
--- a/Makefile
+++ b/Makefile
@@ -478,6 +478,7 @@ $(BUILD_DIR)/include/text_strings.h: $(BUILD_DIR)/include/text_menu_strings.h
 $(BUILD_DIR)/src/menu/file_select.o: $(BUILD_DIR)/include/text_strings.h
 $(BUILD_DIR)/src/menu/star_select.o: $(BUILD_DIR)/include/text_strings.h
 $(BUILD_DIR)/src/game/ingame_menu.o: $(BUILD_DIR)/include/text_strings.h
+$(BUILD_DIR)/src/boot/mem_error_screen.o: $(BUILD_DIR)/include/text_strings.h
 
 
 #==============================================================================#
diff --git a/include/segments.h b/include/segments.h
index a97d6ee8..186c968e 100644
--- a/include/segments.h
+++ b/include/segments.h
@@ -3,6 +3,9 @@
 
 #include "config.h"
 
+/* Use expansion pack RAM */
+#define USE_EXT_RAM 1
+
 /*
  * Memory addresses for segments. Ideally, this header file would not be
  * needed, and the addresses would be defined in sm64.ld and linker-inserted
diff --git a/include/text_strings.h.in b/include/text_strings.h.in
index 749179b1..2f6f7a3c 100644
--- a/include/text_strings.h.in
+++ b/include/text_strings.h.in
@@ -25,6 +25,11 @@
 #define TEXT_PAUSE _("PAUSE") // Pause text, Castle Courses
 #define TEXT_HUD_CONGRATULATIONS _("CONGRATULATIONS") // Course Complete Text, Bowser Courses
 
+// Memory Expansion Error Screen
+#define TEXT_CONSOLE_8MB _("If you're using an N64 console, then you will need to buy an\nExpansion Pak to play this ROM hack.")
+#define TEXT_PJ64 _("If you are using PJ64 1.6, go to:\nOptions > Settings > Rom Settings Tab > Memory Size\nthen select 8 MB from the drop-down box.")
+#define TEXT_PJ64_2 _("If you are using PJ64 2.X, go to:\nOptions > Settings > Config: > Memory Size, select 8 MB")
+
 #if defined(VERSION_JP) || defined(VERSION_SH)
 
 /**
diff --git a/levels/entry.c b/levels/entry.c
index 17c773ed..677a5ae9 100644
--- a/levels/entry.c
+++ b/levels/entry.c
@@ -15,3 +15,12 @@ const LevelScript level_script_entry[] = {
     EXECUTE(/*seg*/ 0x14, /*script*/ _introSegmentRomStart, /*scriptEnd*/ _introSegmentRomEnd, /*entry*/ level_intro_splash_screen),
     JUMP(/*target*/ level_script_entry),
 };
+
+const LevelScript level_script_entry_error_screen[] = {
+    INIT_LEVEL(),
+    SLEEP(/*frames*/ 2),
+    BLACKOUT(/*active*/ FALSE),
+    SET_REG(/*value*/ 0),
+    EXECUTE(/*seg*/ 0x14, /*script*/ _introSegmentRomStart, /*scriptEnd*/ _introSegmentRomEnd, /*entry*/ level_intro_entry_error_screen),
+    JUMP(/*target*/ level_script_entry_error_screen),
+};
diff --git a/levels/intro/geo.c b/levels/intro/geo.c
index 30a87806..6bf7b79a 100644
--- a/levels/intro/geo.c
+++ b/levels/intro/geo.c
@@ -15,6 +15,24 @@
 
 #include "levels/intro/header.h"
 
+const GeoLayout intro_geo_error_screen[] = {
+    GEO_NODE_SCREEN_AREA(0, SCREEN_WIDTH/2, SCREEN_HEIGHT/2, SCREEN_WIDTH/2, SCREEN_HEIGHT/2),
+    GEO_OPEN_NODE(),
+        GEO_ZBUFFER(0),
+        GEO_OPEN_NODE(),
+            GEO_NODE_ORTHO(100),
+            GEO_OPEN_NODE(),
+                GEO_BACKGROUND_COLOR(0x0001),
+            GEO_CLOSE_NODE(),
+        GEO_CLOSE_NODE(),
+        GEO_ZBUFFER(0),
+        GEO_OPEN_NODE(),
+            GEO_ASM(0, geo18_display_error_message),
+        GEO_CLOSE_NODE(),
+    GEO_CLOSE_NODE(),
+    GEO_END(),
+};
+
 // 0x0E0002D0
 const GeoLayout intro_geo_0002D0[] = {
    GEO_NODE_SCREEN_AREA(0, SCREEN_WIDTH/2, SCREEN_HEIGHT/2, SCREEN_WIDTH/2, SCREEN_HEIGHT/2),
diff --git a/levels/intro/header.h b/levels/intro/header.h
index 99277e86..04797cd7 100644
--- a/levels/intro/header.h
+++ b/levels/intro/header.h
@@ -26,4 +26,8 @@ extern const LevelScript script_intro_L3[];
 extern const LevelScript script_intro_L4[];
 extern const LevelScript script_intro_L5[];
 
+extern const GeoLayout intro_geo_error_screen[];
+extern const LevelScript level_intro_entry_error_screen[];
+extern Gfx *geo18_display_error_message(u32 run, UNUSED struct GraphNode *sp44, UNUSED u32 sp48);
+
 #endif
diff --git a/levels/intro/script.c b/levels/intro/script.c
index 04b8fc4c..ca9058c4 100644
--- a/levels/intro/script.c
+++ b/levels/intro/script.c
@@ -18,6 +18,21 @@
 #include "make_const_nonconst.h"
 #include "levels/intro/header.h"
 
+const LevelScript level_intro_entry_error_screen[] = {
+    INIT_LEVEL(),
+    FIXED_LOAD(/*loadAddr*/ _goddardSegmentStart, /*romStart*/ _goddardSegmentRomStart, /*romEnd*/ _goddardSegmentRomEnd),
+    LOAD_YAY0(/*seg*/ 0x07, _intro_segment_7SegmentRomStart, _intro_segment_7SegmentRomEnd),
+    ALLOC_LEVEL_POOL(),
+
+    AREA(/*index*/ 1, intro_geo_error_screen),
+    END_AREA(),
+
+    FREE_LEVEL_POOL(),
+    LOAD_AREA(/*area*/ 1),
+    SLEEP(/*frames*/ 32767),
+    EXIT_AND_EXECUTE(/*seg*/ 0x14, _introSegmentRomStart, _introSegmentRomEnd, level_intro_entry_error_screen),
+};
+
 const LevelScript level_intro_splash_screen[] = {
     INIT_LEVEL(),
     FIXED_LOAD(/*loadAddr*/ _goddardSegmentStart, /*romStart*/ _goddardSegmentRomStart, /*romEnd*/ _goddardSegmentRomEnd),
diff --git a/src/engine/level_script.h b/src/engine/level_script.h
index d41a91c8..7d047236 100644
--- a/src/engine/level_script.h
+++ b/src/engine/level_script.h
@@ -6,6 +6,7 @@
 struct LevelCommand;
 
 extern u8 level_script_entry[];
+extern u8 level_script_entry_error_screen[];
 
 struct LevelCommand *level_script_execute(struct LevelCommand *cmd);
 
diff --git a/src/boot/main.c b/src/boot/main.c
index 1a9d9e7e..f4f7a9e5 100644
--- a/src/boot/main.c
+++ b/src/boot/main.c
@@ -11,6 +11,7 @@
 #include "segments.h"
 #include "game/main.h"
 #include "game/rumble_init.h"
+#include "mem_error_screen.h"
 
 // Message IDs
 #define MESG_SP_COMPLETE 100
@@ -131,6 +132,10 @@ void alloc_pool(void) {
     void *start = (void *) SEG_POOL_START;
     void *end = (void *) SEG_POOL_END;
 
+    // Detect memory size
+    if (does_pool_end_lie_out_of_bounds(end))
+        end = (void *)SEG_POOL_END_4MB;
+
     main_pool_init(start, end);
     gEffectsMemoryPool = mem_pool_init(0x4000, MEMORY_POOL_LEFT);
 }
@@ -336,7 +341,10 @@ void thread3_main(UNUSED void *arg) {
     create_thread(&gSoundThread, 4, thread4_sound, NULL, gThread4Stack + 0x2000, 20);
     osStartThread(&gSoundThread);
 
-    create_thread(&gGameLoopThread, 5, thread5_game_loop, NULL, gThread5Stack + 0x2000, 10);
+    if (!gNotEnoughMemory)
+        create_thread(&gGameLoopThread, 5, thread5_game_loop, NULL, gThread5Stack + 0x2000, 10);
+    else
+        create_thread(&gGameLoopThread, 5, thread5_mem_error_message_loop, NULL, gThread5Stack + 0x2000, 10);
     osStartThread(&gGameLoopThread);
 
     while (TRUE) {
diff --git a/src/boot/mem_error_screen.c b/src/boot/mem_error_screen.c
new file mode 100644
index 00000000..f432927c
--- /dev/null
+++ b/src/boot/mem_error_screen.c
@@ -0,0 +1,104 @@
+/* clang-format off */
+/*
+ * mem_error_screen.inc.c
+ *
+ * This enhancement should be used for ROM hacks that require the expansion pak.
+ *
+ */
+/* clang-format on */
+
+#include <types.h>
+#include "segments.h"
+#include "text_strings.h"
+#include "game_init.h"
+#include "main.h"
+#include "print.h"
+#include "ingame_menu.h"
+#include "segment2.h"
+#include "../engine/level_script.h"
+
+// Ensure that USE_EXT_RAM is defined.
+#ifndef USE_EXT_RAM
+#error You have to define USE_EXT_RAM in 'include/segments.h'
+#endif
+
+// Require 8 MB of RAM, even if the pool doesn't go into extended memory.
+// Change the '8' to whatever MB limit you want.
+// Note: only special emulators allow for RAM sizes above 8 MB.
+#define REQUIRED_MIN_MEM_SIZE 1048576 * 8
+
+u8 gNotEnoughMemory = FALSE;
+u8 gDelayForErrorMessage = 0;
+
+u8 does_pool_end_lie_out_of_bounds(void *end) {
+    u32 endPhy = ((u32) end) & 0x1FFFFFFF;
+    u32 memSize = *((u32 *) 0x80000318);
+
+    if (endPhy > memSize) {
+        gNotEnoughMemory = TRUE;
+        return TRUE;
+    } else {
+        if (memSize < REQUIRED_MIN_MEM_SIZE) {
+            gNotEnoughMemory = TRUE;
+        }
+        return FALSE;
+    }
+}
+
+// If you're using an N64 console, then you will need to buy an\nexpansion pak to play this ROM hack.
+u8 text_console_8mb[] = { TEXT_CONSOLE_8MB };
+
+// If you are using PJ64 1.6, go to: Options ► Settings ► Rom Settings Tab ► Memory Size then select 8
+// MB from the drop-down box.
+u8 text_pj64[] = { TEXT_PJ64 };
+
+// If you are using PJ64 2.X, go to: Options ► Settings ► Config: ► Memory Size, select 8 MB
+u8 text_pj64_2[] = { TEXT_PJ64_2 };
+
+Gfx *geo18_display_error_message(u32 run, UNUSED struct GraphNode *sp44, UNUSED u32 sp48) {
+    if (run) {
+        if (gDelayForErrorMessage > 0) {
+            // Draw color text title.
+            print_text(10, 210, "ERROR    Need more memory");
+
+            // Init generic text rendering
+            create_dl_ortho_matrix();
+            gSPDisplayList(gDisplayListHead++,
+                           dl_ia_text_begin); // Init rendering stuff for generic text
+
+            // Set text color to white
+            gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, 255);
+
+            print_generic_string(8, 170, text_console_8mb);
+            print_generic_string(8, 120, text_pj64);
+            print_generic_string(8, 54, text_pj64_2);
+
+            // Cleanup
+            gSPDisplayList(gDisplayListHead++,
+                           dl_ia_text_end); // Reset back to default render settings.
+            gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW);
+        } else {
+            gDelayForErrorMessage += 1;
+        }
+    }
+
+    return 0;
+}
+
+// Basic main loop for the error screen. Note that controllers are not enabled here.
+void thread5_mem_error_message_loop(UNUSED void *arg) {
+    struct LevelCommand *addr;
+
+    setup_game_memory();
+    set_vblank_handler(2, &gGameVblankHandler, &gGameVblankQueue, (OSMesg) 1);
+
+    addr = segmented_to_virtual(level_script_entry_error_screen);
+
+    render_init();
+
+    while (1) {
+        select_gfx_pool();
+        addr = level_script_execute(addr);
+        display_and_vsync();
+    }
+}
diff --git a/src/game/mem_error_screen.h b/src/game/mem_error_screen.h
new file mode 100644
index 00000000..9fbff34c
--- /dev/null
+++ b/src/game/mem_error_screen.h
@@ -0,0 +1,8 @@
+#ifndef MEM_ERROR_SCREEN_H
+#define MEM_ERROR_SCREEN_H
+
+extern u8 gNotEnoughMemory;
+void thread5_mem_error_message_loop(UNUSED void *arg);
+u8 does_pool_end_lie_out_of_bounds(void *end);
+
+#endif
