Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/ImLukzy/ChefDash/llms.txt

Use this file to discover all available pages before exploring further.

ChefDash structures its challenge around 20 distinct kitchen levels, each defined by how many orders the player must complete, which ingredients are available on the board, a set of possible recipes, and a countdown timer. The first three levels are hand-crafted with curated ingredients and recipes; Levels 4 through 20 are procedurally generated at launch so difficulty scales smoothly without manual tuning. Completing a level with at least one order served unlocks the next level and records a star rating in memory that is displayed on the map.

The Level Struct

Every level in the game is represented by a single Level value type defined in Models/Level.swift:
struct Level: Identifiable {
    let id: Int                          // Level number (1, 2, 3...)
    let name: String                     // Display name shown on the map node
    let targetOrders: Int                // Orders required to pass the level
    let availableIngredients: [String]   // Active ingredient emojis for this level
    let possibleRecipes: [[String]]      // Emoji sequences that can appear as orders
    let baseTime: Int                    // Seconds on the countdown clock

    var isUnlocked: Bool = false         // Whether the player can start this level
    var starsEarned: Int = 0             // Best star rating achieved (0–3)
}
FieldTypeDescription
idIntUnique level number; also used to calculate which level to unlock next.
nameStringHuman-readable name displayed on the map node and in VictoryView.
targetOrdersIntMinimum completed orders needed to achieve at least 1 star.
availableIngredients[String]The ingredient emojis shown on the tappable grid during a round.
possibleRecipes[[String]]Pool of recipes; one is picked at random for each new order.
baseTimeIntStarting timer value in seconds when a round begins.
isUnlockedBoolMutable; set to true by finishRound(starsEarned:) on the subsequent level.
starsEarnedIntMutable; tracks the player’s best rating for the current session (0–3).

Hand-Crafted Levels

The first three levels are authored by hand in setupLevels() with fixed ingredients and recipes designed to onboard new players gradually.
LevelNameTarget OrdersIngredientsTimer
1Burger Station3🍞 🥩 🧀40 s
2Green Diner4🍞 🥩 🧀 🥬 🍅45 s
3Bacon & Grill5🍞 🥩 🧀 🥬 🍅 🥓 🧅50 s
Level 1 ships with isUnlocked: true; Levels 2 and 3 start locked and require the player to earn at least one star on the preceding level.
The ingredient pool emoji order matters — ingredients are added to recipes strictly in the order they appear in availableIngredients. The grid in RecipesView shuffles the display order on every tap for variety, but the recipe sequences always use pool-order positions. Keeping this consistent means procedurally generated recipes are always buildable with the available ingredients.

Procedural Generation (Levels 4–20)

Levels 4 through 20 are named "Kitchen Arcade Expo N" and are generated at app launch using three scaling formulas applied to the level index i:
let poolIngredients = ["🍞", "🥩", "🧀", "🥬", "🍅", "🥓", "🧅", "🍄"]

for i in 4...20 {
    let ingredientCount = min(5 + (i / 5), poolIngredients.count)
    let ingredientsForLevel = Array(poolIngredients.prefix(ingredientCount))

    let target = 4 + (i / 2)

    allLevels.append(
        Level(
            id: i,
            name: "Kitchen Arcade Expo \(i)",
            targetOrders: target,
            availableIngredients: ingredientsForLevel,
            possibleRecipes: [recipeOne, recipeTwo],
            baseTime: max(30, 55 - (i * i / 15)),
            isUnlocked: false,
            starsEarned: 0
        )
    )
}

Scaling Formulas

Ingredient Count

min(5 + (i / 5), 8)Grows from 5 at Level 4 toward the full pool of 8 by Level 20.

Target Orders

4 + (i / 2)Level 4 requires 6 orders; Level 20 requires 14 orders.

Base Timer

max(30, 55 - (i * i / 15))Drops steeply in the mid-game. Floors at 30 seconds from Level 16 onward.

The Ingredient Pool

All 8 ingredients used across the game, in pool order:
["🍞", "🥩", "🧀", "🥬", "🍅", "🥓", "🧅", "🍄"]
Early procedural levels use only the first 6 (no 🧅 or 🍄); only the highest-difficulty levels unlock the full set.

Recipe Validation

Every ingredient tap passes through addIngredient(_:) in GameState, which performs strict positional matching:
func addIngredient(_ emoji: String) {
    currentBurgerStack.append(emoji)

    // Too many ingredients — immediate error
    if currentBurgerStack.count > targetRecipeEmojis.count {
        triggerError()
        return
    }

    // Any positional mismatch — immediate error
    for i in 0..<currentBurgerStack.count {
        if currentBurgerStack[i] != targetRecipeEmojis[i] {
            triggerError()
            return
        }
    }

    // Exact match on full sequence — success
    if currentBurgerStack == targetRecipeEmojis {
        triggerSuccess()
    }
}
Any mismatch at any position calls triggerError(), which resets the combo multiplier to 1, flashes the error overlay, and clears currentBurgerStack after 0.8 seconds. Additionally, RecipesView deducts 3.0 seconds from the timer locally when it detects a wrong ingredient before calling addIngredient.
1

Player taps an ingredient

The emoji is appended to currentBurgerStack.
2

Positional check

Each element of currentBurgerStack is compared at the same index in targetRecipeEmojis. The first mismatch triggers an error immediately.
3

Completion check

If the stack length equals the recipe length and all positions match, triggerSuccess() is called.
4

Next order

After a 0.8-second celebration flash, generateNextOrder() picks a new random recipe from possibleRecipes and resets the stack.

Star Rating Logic

When the timer hits zero in RecipesView, the star count is calculated and passed to finishRound(starsEarned:):
let estrellasFinales = completadas >= target ? 3
    : (completadas >= max(1, target / 2) ? 2
    : (completadas > 0 ? 1 : 0))
ConditionStars
completadas >= targetOrders⭐⭐⭐
completadas >= max(1, targetOrders / 2)⭐⭐
completadas > 0
completadas == 0(none)
The same formula is mirrored in VictoryView to render the three star icons on the results screen.

Level Unlocking

finishRound(starsEarned:) runs on the main queue after every round. It records the best star rating in memory and unlocks the next level by ID:
func finishRound(starsEarned: Int) {
    DispatchQueue.main.async {
        if starsEarned > 0 {
            if self.selectedLevelIndex < self.levels.count {
                // Persist best star count
                self.levels[self.selectedLevelIndex].starsEarned =
                    max(self.levels[self.selectedLevelIndex].starsEarned, starsEarned)

                // Unlock the next level by ID
                let currentLevelId = self.levels[self.selectedLevelIndex].id
                let nextLevelId = currentLevelId + 1

                if let nextLevelIndex = self.levels.firstIndex(where: { $0.id == nextLevelId }) {
                    self.levels[nextLevelIndex].isUnlocked = true
                }
            }
        }
    }
}
A level is only unlocked when the player earns at least 1 star (starsEarned > 0). Completing zero orders — running out of time immediately — leaves the next level locked. Star ratings are tracked as the in-session best: replaying a level with a lower score will not overwrite a previous high within the same session.

Build docs developers (and LLMs) love