Grout

Have you ever had an extra hour or two between classes? Do you suck at time management? Then you're familiar with the regret of wasted hours. We built Grout to help you boost your productivity.

Navigating the average productivity app is a task in and of itself. Time estimation, prioritization, and organization of tasks? No thanks. Grout simplifies the process for you: add some tasks to-do list style, then tell it how long you have to work, and Grout will create a custom work session for you.

The best part? Grout saves your data, and uses it to improve time estimations to be more accurate in the future, based on how long it takes you to complete similar tasks.

Mixing Grout (How We Made It)

Grout started humbly: A sketchbook page, then a Miro board. We drafted the UI to be user-focused, emphasizing simple utility. Any element that we could automate or remove, we did so, to minimize barriers between sitting down and getting work done.

We used react-native with the Expo router, and Tamagui UI to build Grout.

How It Works

Figuring out the best way to find similarities between tasks with little to no information was a neat challenge. We initially planned on using user-defined categories, but decided that was too much work for the user (selecting another thing? almost 2x the effort). Initially, we were using Levenshtein distance to calculate similarity scores for task titles, but it fails to capture semantic similarity or reordered terms. We landed on offering two options to the user:

  • Local: Uses the winkNLP library's bm25 engine to find the most similar tasks. Preprocesses inputs by tokenizing, extracting stems, and including synonyms when searching, as well as fuzzy matching tokens to previously seen tokens to account for spelling errors. It can be pretty accurate (e.g. recognizing quizzes or homework being said in different places), but fails to consider meaning (like how a quiz is like a smaller test).
  • Cloud: Obtains vector embeddings of task titles using the Gemini Embedding API through OpenRouter, caching past embeddings on-device. Computes cosine similarity between vectors to find the most similar past tasks.

For both of these, we had to experiment with how to actually predict the time based off of similarity scores. Grout currently: takes the top 3 most similar past tasks to a given task; raises their similarity score to the 8th power; sums their similarity scores and their times taken * similarity scores; and divides the result by the total similarity scores. This allows for consideration of multiple similar tasks, while maintaining a steep falloff for tasks that are not very similar.

$$ prediction = \frac{\sum{timetaken * similarity^8}}{\sum{similarity^8}} $$

If the model can't find any tasks that are similar (this only happens with the NLP model, the embeddings just end up with very low similarity), it uses a user-defined default time estimate and continues to refine its guesses after they do some tasks.

Challenges We Overcame

We had never used React Native or any of the other parts of our tech stack before, so we ran into plenty of hurdles.

However, despite all the challenges, we learned and accomplished a lot. We learned:

  • Our biggest lesson about package management: make sure everyone's on the same page with Node versions (right from the beginning, it was hard to get started).

  • How to parse the documentation spread across all 4 platforms (React, React Native, Expo, Tamagui), using context clues and background knowledge to rectify incomplete and even conflicting information.

  • How to use Expo Router. It's limitations led to a lot of issues defining the early structure of our app, but we eventually were able to leverage it to simplify our navigation, saving us hours of setup.

  • The benefits of Tamagui. It's UI components and enforcement of global styles led to a pleasing and minimalistic design that maintained consistency across Grout's pages.

  • How to use various libraries (expo-sqlite, react-native-reanimated)

Thanks for checking out Grout!

Share this project:

Updates