A title card, not a loading screen.
Hirely opens like a studio ident: the wordmark strikes in with a red bloom and a glowing horizon, then hands off to Home. It sets the cinematic tone before a single job appears.
What if job hunting felt like browsing your favourite streaming app?
A cinematic, dark job-discovery app: a hero billboard of featured roles, a Top 10 row with giant outlined numerals, poster carousels, “98% Match” scores and an apply flow that ends in a confetti burst.
Scroll through Hirely the way a user meets it, from first launch to the last tab. Each chapter is a real simulator capture.
Hirely opens like a studio ident: the wordmark strikes in with a red bloom and a glowing horizon, then hands off to Home. It sets the cinematic tone before a single job appears.
A full-bleed billboard carousel auto-advances through featured jobs, tinting the whole backdrop to each poster and tilting cards in 3D as they slide. Filter pills reshape the feed in place.
“Continue your applications” with progress bars, a Top 10 row with giant outlined numerals, then poster and wide carousels by category. Every poster is drawn in code from brand gradients and SF Symbols.
The hero parallaxes under your thumb while the match score, salary and work mode stay legible. Overview, Company and More Like This tabs slide an animated indicator between them.
The Apply button morphs into a spinner, resolves to “Applied ✓”, fires a success haptic and throws confetti. A tiny moment that makes a stressful task feel rewarding.
Trending chips and category tiles push into their own screens; typing switches to live results you can narrow to Remote, Hybrid or On-site without losing your place.
Saved roles live as posters; applications become a tracker that moves from Applied → Screening → Interview → Offer, with each stage colour-coded at a glance.
A profile-strength ring, saved / applied / interview stats and an Open to Work toggle, backed by a full settings stack with notifications and résumé management.
Modern SwiftUI end to end, with no third-party UI libraries. All data is static and mocked so the craft stays front and centre.
A single @Observable JobStore owns jobs, saved roles and applications, injected once through .environment, so every tab reacts without view models fighting over state.
@Observable
final class JobStore {
var jobs: [Job] = Job.catalog // 24 roles, 12 companies
var saved: Set<Job.ID> = []
var applications: [Application] = []
func apply(to job: Job) {
applications.append(.init(job: job, stage: .applied))
}
}
@main struct HirelyApp: App {
@State private var store = JobStore()
var body: some Scene {
WindowGroup { RootView().environment(store) }
}
}Four tabs declared with the new Tab type, with a live badge on My List.
TabView(selection: $tab) {
Tab("Home",
systemImage: "house",
value: .home) { HomeView() }
// Search · Profile …
Tab("My List",
systemImage: "bookmark",
value: .list) { MyListView() }
.badge(store.saved.count)
}The hero carousel snaps view-by-view, tracks its page with ScrollPosition and tilts neighbours in 3D through scrollTransition.
ScrollView(.horizontal) {
LazyHStack(spacing: 0) {
ForEach(featured) { job in
HeroCard(job: job)
.scrollTransition { view, phase in
view.rotation3DEffect(
.degrees(phase.value * -12),
axis: (0, 1, 0))
}
}
}
.scrollTargetLayout()
}
.scrollTargetBehavior(.viewAligned)
.scrollPosition($position)Idle → loading → applied, with a success haptic and a confetti overlay keyed off the same state.
Button(action: apply) {
switch state {
case .idle: Label("Apply", systemImage: "paperplane")
case .loading: ProgressView()
case .applied: Label("Applied", systemImage: "checkmark")
}
}
.contentTransition(.symbolEffect(.replace))
.sensoryFeedback(.success, trigger: state == .applied)
.overlay { if state == .applied { ConfettiBurst() } }Every poster is a brand gradient plus an SF Symbol, generated per company.
job.brand.gradient
.overlay(alignment: .topTrailing) {
Image(systemName: job.symbol)
.font(.system(size: 120,
weight: .black))
.opacity(0.18)
}The detail hero reads its scroll offset directly, with no GeometryReader hacks.
.onScrollGeometryChange(
for: CGFloat.self
) { $0.contentOffset.y }
action: { _, y in
heroOffset = y
}The .xcodeproj is generated from a spec file, so there are no merge conflicts in project files.
name: Hirely
targets:
Hirely:
type: application
platform: iOS
deploymentTarget: "18.0"
sources: [Sources]This is QA-automation thinking applied to marketing assets. A launch argument puts the app in demo mode, a driver walks the real UI, and OSLog markers tell a recorder exactly when to grab each frame. When the design changes, every asset is regenerated with one command.
-demoMode launch argumentSHOT markerssimctl records and snaps on cue22 screens + a 1:22 walkthrough, zero hand-edited frames
import OSLog
let demo = Logger(subsystem: "com.aya.hirely", category: "demo")
if CommandLine.arguments.contains("-demoMode") {
Task { await DemoDriver(store: store).run() }
}
// DemoDriver drives the real UI, then marks the frame
await show(.jobDetail(featured[0]))
demo.notice("SHOT 08-detail-hero")xcrun simctl io booted recordVideo demo.mov &
xcrun simctl launch --console booted com.aya.hirely -demoMode |
while read line; do # every SHOT marker = one frame
[[ $line == *SHOT* ]] || continue
xcrun simctl io booted screenshot "${line##* }.png"
doneEvery tab, sheet and transition, recorded straight from the iOS simulator by the automated demo driver.
Muted · 1:22 · 590×1280 simulator capture