Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .Jules/palette.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,7 @@
## 2026-02-13 - Tactile Feedback in CLI
**Learning:** In terminal-based games, users expect immediate visual feedback for their actions. Relying on a periodic "tick" to update the UI creates a laggy feel. Using `poll()` with a dynamic timeout allows the application to remain idle yet wake up instantly to process and render user input.
**Action:** Always trigger a UI refresh immediately after processing user input in CLI applications, and use efficient waiting mechanisms (like `poll`) that can be interrupted by input.

## 2026-02-24 - Game Session Flow
**Learning:** Immediate game start without a "Ready?" prompt can catch users off guard. Adding a "Press any key to start" step improves session readiness. Also, hiding the cursor during gameplay reduces visual noise and increases immersion in CLI games.
**Action:** Always implement a start prompt and cursor hiding for interactive CLI games.
15 changes: 12 additions & 3 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,16 @@
#define CLR_NORM "\033[1;32m"
#define CLR_CTRL "\033[1;33m"
#define CLR_RESET "\033[0m"
#define HIDE_CURSOR "\033[?25l"
#define SHOW_CURSOR "\033[?25h"

struct termios oldt;

void restore_terminal(int signum) {
tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
// Use write() and _exit() because they are async-signal-safe
const char* msg = "\033[0m\n\nGame interrupted. Terminal settings restored.\n";
write(STDOUT_FILENO, msg, 52);
const char* msg = SHOW_CURSOR "\033[0m\n\nGame interrupted. Terminal settings restored.\n";
write(STDOUT_FILENO, msg, 58);
_exit(signum);
}

Expand All @@ -51,6 +53,13 @@ int main() {
<< "Controls:\n " << CLR_CTRL << "[h]" << CLR_RESET << " Toggle Hard Mode (10x Speed!)\n "
<< CLR_CTRL << "[q]" << CLR_RESET << " Quit Game\n " << CLR_CTRL << "[Any key]" << CLR_RESET << " Click!\n\n";

std::cout << "Press any key to start... (q to quit)" << std::flush;
if (read(STDIN_FILENO, &input, 1) > 0 && input == 'q') {
tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
return 0;
}
std::cout << HIDE_CURSOR;

struct pollfd fds[1] = {{STDIN_FILENO, POLLIN, 0}};
auto last_tick = std::chrono::steady_clock::now();
bool updateUI = true;
Expand Down Expand Up @@ -86,6 +95,6 @@ int main() {
}
}
tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
std::cout << "\n\n" << CLR_SCORE << "Final Score: " << score << CLR_RESET << "\nThanks for playing!\n";
std::cout << SHOW_CURSOR << "\n\n" << CLR_SCORE << "Final Score: " << score << CLR_RESET << "\nThanks for playing!\n";
return 0;
}