Numengames Website Developer Guide
Welcome to the Numengames website project! Whether you're a seasoned team member or just joining us on this journey, this guide will be your compass through our codebase. We've designed this documentation to help you understand not just what our code does, but why we've structured it the way we have.
Project Overview
The Numengames website represents our digital front door - a place where users first experience our brand and products. To create a seamless, performant experience, we've built it using:
- Astro for static site generation and page routing
- Svelte for interactive components
- TypeScript for type safety
- Tailwind CSS for styling
We've embraced a component-based architecture with clear separation of concerns, allowing us to build features collaboratively while maintaining consistency.
Directory Structure
Our project follows a thoughtful organization that reflects how components and features relate to each other:
src/
├── components/
│ ├── ui/ # Reusable UI components
│ │ ├── buttons/ # Button components
│ │ ├── typography/ # Text components (Heading, Paragraph)
│ ├── layout/ # Layout components
│ │ ├── sections/ # Section wrappers
│ ├── features/ # Feature-specific components
│ │ ├── hero/ # Hero section components
│ │ │ ├── HeroSection.astro
│ │ │ ├── HeroContent.astro
├── hooks/ # Custom Svelte hooks
├── stores/ # Svelte stores for state management
├── layouts/ # Page layout templates
├── pages/ # Page components and routes
├── i18n/ # Internationalization
├── styles/ # Global styles
└── types/ # TypeScript type definitions
Think of our codebase as a city - UI components are the building blocks, layouts create the streets and infrastructure, and features are the distinctive neighborhoods that make our city unique.
Component Organization
UI Components
Like the atoms and molecules in a design system, our UI components in src/components/ui/
are the fundamental building blocks. They're organized by category to make them easy to discover:
- Typography: Text components such as
Heading.astro
andParagraph.astro
ensure consistent text presentation - Buttons: Button components like
Button.astro
provide interactive elements with consistent styling
When working with UI components, remember they should be:
- Pure: Like good ingredients in a recipe, they should do one thing well with minimal complexity
- Reusable: Designed to work across multiple features without modification
- Configurable: Flexible enough to adapt to different needs through props
Layout Components
In src/components/layout/
, you'll find the structural elements that give our pages their shape:
- Section.astro: A wrapper that provides consistent spacing, width constraints, and structural elements
Think of layout components as the blueprints for our site - they define spaces but don't determine what goes inside them. They should:
- Provide consistent structure across the application
- Handle responsive layouts gracefully
- Remain agnostic to the specific content they contain
Feature Components
This is where our website comes to life. In src/components/features/
, we combine UI and layout components to create meaningful user experiences, organized by functionality:
- HeroSection.astro: The welcoming face of a page that captures attention
- HeroContent.astro: The specific messaging and call-to-action within the hero
When building feature components, imagine them as complete experiences that should:
- Tell a coherent story about a specific functionality
- Combine UI and layout components into something greater than the sum of its parts
- Handle any feature-specific logic or state
Styling with Tailwind CSS
Configuration
Colors, spacing, typography - these design decisions define our visual identity. We've captured them in tailwind.config.cjs
at the root of the project:
// Example of color configuration in tailwind.config.cjs
colors: {
primary: {
beige: '#F9EBDC',
coralRed: '#F35059',
darkRed: '#D33440',
panther: '#212123',
mediterranean: '#A6DAD5'
},
light: {
background: '#F9F9F9',
text: '#212123',
accent: '#F35059',
muted: '#717171',
},
dark: {
background: '#212123',
text: '#F9EBDC',
accent: '#F35059',
muted: '#909091',
}
}
Important: Our default persona is nocturnal! The project currently uses dark mode as the default theme. The
dark
class is applied to the HTML element by default, with our theme switcher allowing users to step into the light if they prefer.
Global Styles
Our global styling foundation in src/styles/global.css
includes:
- Base styles and Tailwind directives that set the stage
- Font declarations that give our text its voice
- Theme-specific styles that adapt to light and dark modes
- Utility classes that solve common styling challenges
Component Styling Best Practices
When styling components, follow these principles:
- Embrace Tailwind's utility-first approach - it keeps styles close to the components they affect
- Create consistent component variants using the
className
prop pattern to maintain predictability - Lean on theme variables instead of hard-coding values, making site-wide changes more manageable
- Design with both light and dark in mind using our theme variables
CSS Custom Components
For styles that deserve to be reused, we've created custom component classes in the @layer components
section of global.css
:
@layer components {
.hero-title {
@apply text-6xl leading-tight 2xl:text-7xl 2xl:leading-tight font-medium tracking-[-0.03em];
}
.theme-card {
@apply bg-light-background border border-light-muted/20 dark:bg-dark-background dark:border-dark-muted/20;
}
}
These act as shortcuts for frequently used style combinations, helping us maintain consistency while reducing repetition.
State Management
Stores
Not everything belongs in component state. For information that needs to be accessible across the application, we use Svelte stores in src/stores/
:
- theme.ts: Remembers whether the user prefers to walk in darkness or light
- locale.ts: Keeps track of which language is currently speaking to the user
All stores are conveniently re-exported from index.ts
, saving you from import gymnastics.
Hooks
Custom Svelte hooks in src/hooks/
package reusable logic that components can tap into:
- useMediaQuery.ts: Listens for changes in viewport size so components can adapt
Each hook should focus on telling one story well - handling a single responsibility and sharing its wisdom with any component that asks.
Internationalization (i18n)
Our website speaks multiple languages through:
- URL-based locale routing (
/[locale]/page
) that identifies the user's language preference - Translation objects in the
i18n/
directory that provide the vocabulary - A locale store that remembers the current language setting
Best Practices
Component Organization
-
Follow the Component Hierarchy: Start with the basics (UI), add structure (layout), then create experiences (features) - this mental model helps maintain clarity.
-
Component Naming:
- PascalCase for component names makes them stand out in imports
- Suffixes like
.astro
and.svelte
clearly identify the component type - Descriptive names tell developers what the component does before they even open the file
-
File Organization:
- Group related components in feature-specific directories to tell a cohesive story
- Use index files to simplify imports and keep your code cleaner
State Management
-
Local vs. Global State:
- Component state is like personal belongings - keep them close when they're only needed locally
- Stores are for information that needs to travel - use them sparingly but confidently for truly global state
-
Store Organization:
- Each store should tell one clear story about one aspect of application state
- The index.ts re-export pattern keeps imports tidy across the application
TypeScript
- Type Definitions:
- Shared types in the
types/
directory create a common language for the entire codebase - Specific types for component props set clear expectations about what data components need
- Avoiding
any
prevents the frustrating bugs that come from type ambiguity
- Shared types in the
Responsive Design
- Mobile-First Approach:
- We design for the smallest screen first, then enhance for larger viewports
- The
useMediaQuery
hook helps components adapt their behavior to different screen sizes - Tailwind's responsive classes make responsive styling intuitive and visual
Adding New Features
When you're tasked with bringing a new feature to life, follow this narrative arc:
-
Identify UI Components:
- Start by looking through our existing UI components - can they tell your story?
- Only add new UI components when you need a building block that doesn't exist yet
-
Create Feature Components:
- Carve out a home for your feature in
components/features/
- Combine existing UI and layout components to craft your user experience
- Carve out a home for your feature in
-
Add State Management:
- Determine if your feature needs to remember things beyond its own boundaries
- If so, add a store that manages just what you need, nothing more
-
Add Internationalization:
- Ensure your feature can speak to users in all the languages we support
- Add translations that maintain the tone and meaning across languages
Resources and References
Design Resources
- Figma Design: Explore our visual language and component specifications in Figma
- Brand Guidelines: The colors, typography, and styles that give our brand its distinctive voice
Development References
- Astro Documentation: https://docs.astro.build
- Svelte Documentation: https://svelte.dev/docs
- Tailwind CSS Documentation: https://tailwindcss.com/docs
Conclusion
This guide isn't just documentation - it's a shared understanding of how we build together. By following these patterns and practices, we create a codebase that's greater than the sum of its parts - one that's maintainable, extensible, and a joy to work with.
As you navigate through our components and features, remember that everything has its place and purpose. The clear separation of UI, layout, and feature components creates a natural workflow that makes it easier to understand existing code and contribute new features with confidence.
Welcome to the team - we're excited to see what you'll build with us!