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-10-24 - Pre-start Prompts and Cursor Visibility
**Learning:** For interactive CLI games, automatically starting the game and timer immediately upon executing the binary creates a jarring user experience, as the user is rarely ready to start playing instantly. Additionally, the presence of a blinking cursor during rapid UI updates is distracting and reduces visual polish. Providing an explicit "Press any key to start" action gives the user control, while hiding the cursor during active gameplay (`\033[?25l`) and restoring it upon exit (`\033[?25h`) makes the terminal feel more like a dedicated application than a raw command-line interface.
**Action:** Always require an explicit user action to start a CLI interactive loop and always hide the terminal cursor during active rendering (ensuring it is safely restored on normal exit and via signal handlers).
10 changes: 8 additions & 2 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ 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[] = "\033[?25h\033[0m\n\nGame interrupted. Terminal settings restored.\n";
write(STDOUT_FILENO, msg, sizeof(msg) - 1);
_exit(signum);
}

Expand All @@ -51,6 +51,11 @@ 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..." << std::flush;
read(STDIN_FILENO, &input, 1);
std::cout << "\r \r";
std::cout << "\033[?25l" << std::flush;

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 +91,7 @@ int main() {
}
}
tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
std::cout << "\033[?25h"; // Restore cursor
std::cout << "\n\n" << CLR_SCORE << "Final Score: " << score << CLR_RESET << "\nThanks for playing!\n";
return 0;
}