Overview
Compufy Technology is a corporate marketing website that presents the company's brand identity, service offerings, team information, and contact capabilities through a modern, high-performance web experience.
Built with a spec-driven development methodology — requirements, design, and tasks documented before a single line of code was written. The result is a production-grade Angular application with SSR, OnPush change detection, Angular Signals, and a comprehensive test suite.
"Most corporate websites are purely informational. Compufy embeds a fully functional 2D rocket game directly on top of the page — where every visible DOM element becomes a destructible target."
Tech Stack
Frontend
- Angular 18.2 — standalone components, no NgModules
- TypeScript 5.5 — strict mode throughout
- Tailwind CSS 3.4 — utility-first, dark-mode via class strategy
- Angular Signals — signal, computed, effect for zero-boilerplate state
- Lucide-Angular — tree-shakeable SVG icons
Backend & Infrastructure
- Angular SSR 18 — server-side rendering via Express 4
- Firebase 12 — Firestore for contact form, Analytics for production tracking
- @angular/fire 18 — typed Firebase integration
- RxJS 7.8 — HTTP streams via HttpService wrapper
Architecture
The application follows a feature-based folder structure with lazy-loaded routes, a pure data layer, and a centralized error boundary.
Browser
└── Angular Universal (SSR)
├── Express Server ──────────────► Firebase (Firestore / Analytics)
└── Angular SPA
├── AppComponent (root shell + navbar + game overlay)
├── Lazy-loaded Feature Routes
│ ├── HomeComponent
│ ├── ServicesComponent / ServiceDetailsComponent
│ ├── ContactComponent
│ ├── WhoWeAreComponent
│ ├── CareersComponent
│ └── AiApproachComponent
├── Shared UI Components (Button, Card, Input, SkeletonLoader)
├── Core Services (Firebase, HttpService, ErrorHandler)
└── Rocket Game Overlay (canvas-based, SSR-safe)
Design Patterns
- Standalone components — no NgModules; each component declares its own imports
- OnPush change detection — all components use OnPush for minimal re-renders
- Signal-first reactivity — local and shared state via Angular Signals; RxJS reserved for HTTP only
- Functional DI — inject() used throughout instead of constructor injection
- Pure data layer — src/app/data/ contains only interfaces, constants, and static data with zero Angular dependencies
The Rocket Game Easter Egg
A fully modular canvas-based mini-game embedded as an easter egg — activated via a gamepad button in the navbar, available on every page.
How It Works
- The rocket flies over the live page content
- All visible DOM elements — headings, cards, buttons, nav links — become destructible targets
- Targets are auto-discovered at activation time via getBoundingClientRect; no manual tagging required
- Break animation plays on destruction; elements fade and fall
- Particle explosion effect on hit
- Auto-scrolls the page as the rocket approaches viewport edges
- Full mobile support via virtual D-pad and fire button
Game Modules
- entities.ts — TypeScript interfaces: Rocket, Bullet, Particle, GameState
- input-handler.ts — keyboard event capture + touch state injection
- target-cache.ts — auto-discovers all shootable DOM elements; refreshes rects each frame
- collision-handler.ts — pure AABB intersection functions; no DOM access
- renderer.ts — all Canvas 2D draw calls; pure functions with save()/restore() symmetry
- game-engine.ts — RAF loop, physics, bullet/particle lifecycle, collision delegation
Performance Optimizations
Code Splitting
Every feature route uses loadComponent with dynamic import(). The browser only downloads the JavaScript for a page when the user navigates to it. Initial bundle contains only the root shell.
SSR + Hydration
Angular Universal pre-renders HTML on the server. Users see fully rendered content on first load without waiting for JavaScript — improving Core Web Vitals (LCP, FCP) and SEO indexability.
OnPush + Signals
Angular only checks a component's template when its Signal inputs change or an event fires within it — not on every global tick. Updates are surgical and targeted.
Tree-Shakeable Icons
Lucide icons are registered explicitly in app.config.ts. Only the icons actually used are included in the production bundle — no icon font bloat.
Testing Strategy
The project uses a two-layer testing approach: concrete unit tests with Jasmine 5 + Karma 6, and property-based tests with fast-check 4 running 100+ iterations per property.
Correctness Properties (PBT)
- P1: Rocket bounds clamping — rocket always stays within canvas bounds for any canvas size
- P2: Friction convergence — applying friction 0.85 repeatedly never increases speed
- P3: Bullet count cap — active bullet count never exceeds 20
- P4: OOB bullet removal — bullets outside canvas bounds are removed after one tick
- P5: AABB correctness — collision detection matches reference implementation for arbitrary rect pairs
- P6: Delta-time cap — computed dt never exceeds 0.05s for any timestamp pair
- P7: Particle opacity — opacity always in [0, 1] for any particle and timestamp
- P8: Fire-rate limit — no two consecutive fire events less than 200ms apart
Built with Spec-Driven + Agentic AI
The project was built following a spec-driven development methodology using Kiro, an agentic AI IDE. Before any code was written, the agent produced formal specification documents — requirements, design, and a granular task list — then implemented each task sequentially with tests validating every correctness property.
"The human role was to describe the problem, review outputs, and report what was wrong. The agent handled requirements, architecture, implementation, testing, and debugging — end to end."
