diff --git a/dist/GrowthLapse.app/Contents/Info.plist b/dist/GrowthLapse.app/Contents/Info.plist
new file mode 100644
index 0000000..5c7811f
--- /dev/null
+++ b/dist/GrowthLapse.app/Contents/Info.plist
@@ -0,0 +1,32 @@
+
+
+
+
+ CFBundleDevelopmentRegion
+ de
+ CFBundleDisplayName
+ GrowthLapse
+ CFBundleExecutable
+ GrowthLapse
+ CFBundleIconFile
+ GrowthLapse.icns
+ CFBundleIdentifier
+ de.mike-i386.GrowthLapse
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundleName
+ GrowthLapse
+ CFBundlePackageType
+ APPL
+ CFBundleShortVersionString
+ 0.1.0
+ CFBundleVersion
+ 1
+ LSMinimumSystemVersion
+ 13.0
+ NSHighResolutionCapable
+
+ NSSupportsAutomaticGraphicsSwitching
+
+
+
diff --git a/dist/GrowthLapse.app/Contents/MacOS/GrowthLapse b/dist/GrowthLapse.app/Contents/MacOS/GrowthLapse
new file mode 100755
index 0000000..ce01ddc
Binary files /dev/null and b/dist/GrowthLapse.app/Contents/MacOS/GrowthLapse differ
diff --git a/dist/GrowthLapse.app/Contents/Resources/GrowthLapse.icns b/dist/GrowthLapse.app/Contents/Resources/GrowthLapse.icns
new file mode 100644
index 0000000..b57e077
Binary files /dev/null and b/dist/GrowthLapse.app/Contents/Resources/GrowthLapse.icns differ
diff --git a/dist/GrowthLapse.app/Contents/_CodeSignature/CodeResources b/dist/GrowthLapse.app/Contents/_CodeSignature/CodeResources
new file mode 100644
index 0000000..e52a789
--- /dev/null
+++ b/dist/GrowthLapse.app/Contents/_CodeSignature/CodeResources
@@ -0,0 +1,128 @@
+
+
+
+
+ files
+
+ Resources/GrowthLapse.icns
+
+ G4b+0pcQtmuC7+3xzqOoSKZ6TdM=
+
+
+ files2
+
+ Resources/GrowthLapse.icns
+
+ hash2
+
+ oKK6OTT0Y0tD1lvaxWNP1djCSVl/FaaE8s+cm0CEg50=
+
+
+
+ rules
+
+ ^Resources/
+
+ ^Resources/.*\.lproj/
+
+ optional
+
+ weight
+ 1000
+
+ ^Resources/.*\.lproj/locversion.plist$
+
+ omit
+
+ weight
+ 1100
+
+ ^Resources/Base\.lproj/
+
+ weight
+ 1010
+
+ ^version.plist$
+
+
+ rules2
+
+ .*\.dSYM($|/)
+
+ weight
+ 11
+
+ ^(.*/)?\.DS_Store$
+
+ omit
+
+ weight
+ 2000
+
+ ^(Frameworks|SharedFrameworks|PlugIns|Plug-ins|XPCServices|Helpers|MacOS|Library/(Automator|Spotlight|LoginItems))/
+
+ nested
+
+ weight
+ 10
+
+ ^.*
+
+ ^Info\.plist$
+
+ omit
+
+ weight
+ 20
+
+ ^PkgInfo$
+
+ omit
+
+ weight
+ 20
+
+ ^Resources/
+
+ weight
+ 20
+
+ ^Resources/.*\.lproj/
+
+ optional
+
+ weight
+ 1000
+
+ ^Resources/.*\.lproj/locversion.plist$
+
+ omit
+
+ weight
+ 1100
+
+ ^Resources/Base\.lproj/
+
+ weight
+ 1010
+
+ ^[^/]+$
+
+ nested
+
+ weight
+ 10
+
+ ^embedded\.provisionprofile$
+
+ weight
+ 20
+
+ ^version\.plist$
+
+ weight
+ 20
+
+
+
+
diff --git a/dist/GrowthLapse.iconset/icon_128x128.png b/dist/GrowthLapse.iconset/icon_128x128.png
new file mode 100644
index 0000000..61090d8
Binary files /dev/null and b/dist/GrowthLapse.iconset/icon_128x128.png differ
diff --git a/dist/GrowthLapse.iconset/icon_128x128@2x.png b/dist/GrowthLapse.iconset/icon_128x128@2x.png
new file mode 100644
index 0000000..93549cb
Binary files /dev/null and b/dist/GrowthLapse.iconset/icon_128x128@2x.png differ
diff --git a/dist/GrowthLapse.iconset/icon_16x16.png b/dist/GrowthLapse.iconset/icon_16x16.png
new file mode 100644
index 0000000..1e16cc4
Binary files /dev/null and b/dist/GrowthLapse.iconset/icon_16x16.png differ
diff --git a/dist/GrowthLapse.iconset/icon_16x16@2x.png b/dist/GrowthLapse.iconset/icon_16x16@2x.png
new file mode 100644
index 0000000..9857e23
Binary files /dev/null and b/dist/GrowthLapse.iconset/icon_16x16@2x.png differ
diff --git a/dist/GrowthLapse.iconset/icon_256x256.png b/dist/GrowthLapse.iconset/icon_256x256.png
new file mode 100644
index 0000000..93549cb
Binary files /dev/null and b/dist/GrowthLapse.iconset/icon_256x256.png differ
diff --git a/dist/GrowthLapse.iconset/icon_256x256@2x.png b/dist/GrowthLapse.iconset/icon_256x256@2x.png
new file mode 100644
index 0000000..8a838f8
Binary files /dev/null and b/dist/GrowthLapse.iconset/icon_256x256@2x.png differ
diff --git a/dist/GrowthLapse.iconset/icon_32x32.png b/dist/GrowthLapse.iconset/icon_32x32.png
new file mode 100644
index 0000000..9857e23
Binary files /dev/null and b/dist/GrowthLapse.iconset/icon_32x32.png differ
diff --git a/dist/GrowthLapse.iconset/icon_32x32@2x.png b/dist/GrowthLapse.iconset/icon_32x32@2x.png
new file mode 100644
index 0000000..0920e3d
Binary files /dev/null and b/dist/GrowthLapse.iconset/icon_32x32@2x.png differ
diff --git a/dist/GrowthLapse.iconset/icon_512x512.png b/dist/GrowthLapse.iconset/icon_512x512.png
new file mode 100644
index 0000000..8a838f8
Binary files /dev/null and b/dist/GrowthLapse.iconset/icon_512x512.png differ
diff --git a/dist/GrowthLapse.iconset/icon_512x512@2x.png b/dist/GrowthLapse.iconset/icon_512x512@2x.png
new file mode 100644
index 0000000..62d169a
Binary files /dev/null and b/dist/GrowthLapse.iconset/icon_512x512@2x.png differ
diff --git a/dist/make_growthlapse_icon.swift b/dist/make_growthlapse_icon.swift
new file mode 100644
index 0000000..d1e6b5f
--- /dev/null
+++ b/dist/make_growthlapse_icon.swift
@@ -0,0 +1,127 @@
+import AppKit
+import Foundation
+
+let output = URL(fileURLWithPath: CommandLine.arguments.dropFirst().first ?? "dist/GrowthLapse.iconset")
+try FileManager.default.createDirectory(at: output, withIntermediateDirectories: true)
+
+struct IconFile {
+ let name: String
+ let size: Int
+}
+
+let files = [
+ IconFile(name: "icon_16x16.png", size: 16),
+ IconFile(name: "icon_16x16@2x.png", size: 32),
+ IconFile(name: "icon_32x32.png", size: 32),
+ IconFile(name: "icon_32x32@2x.png", size: 64),
+ IconFile(name: "icon_128x128.png", size: 128),
+ IconFile(name: "icon_128x128@2x.png", size: 256),
+ IconFile(name: "icon_256x256.png", size: 256),
+ IconFile(name: "icon_256x256@2x.png", size: 512),
+ IconFile(name: "icon_512x512.png", size: 512),
+ IconFile(name: "icon_512x512@2x.png", size: 1024),
+]
+
+func drawIcon(size: Int) throws -> Data {
+ let rep = NSBitmapImageRep(
+ bitmapDataPlanes: nil,
+ pixelsWide: size,
+ pixelsHigh: size,
+ bitsPerSample: 8,
+ samplesPerPixel: 4,
+ hasAlpha: true,
+ isPlanar: false,
+ colorSpaceName: .deviceRGB,
+ bytesPerRow: 0,
+ bitsPerPixel: 0
+ )!
+
+ NSGraphicsContext.saveGraphicsState()
+ NSGraphicsContext.current = NSGraphicsContext(bitmapImageRep: rep)
+ let scale = CGFloat(size) / 1024
+ let canvas = NSRect(x: 0, y: 0, width: CGFloat(size), height: CGFloat(size))
+ NSColor.clear.setFill()
+ canvas.fill()
+
+ func rect(_ x: CGFloat, _ y: CGFloat, _ w: CGFloat, _ h: CGFloat) -> NSRect {
+ NSRect(x: x * scale, y: y * scale, width: w * scale, height: h * scale)
+ }
+
+ let bg = NSBezierPath(roundedRect: rect(72, 72, 880, 880), xRadius: 210 * scale, yRadius: 210 * scale)
+ bg.addClip()
+ let gradient = NSGradient(colors: [
+ NSColor(calibratedRed: 0.06, green: 0.35, blue: 0.90, alpha: 1.0),
+ NSColor(calibratedRed: 0.10, green: 0.72, blue: 0.58, alpha: 1.0)
+ ])!
+ gradient.draw(in: canvas, angle: 38)
+
+ NSColor(calibratedWhite: 1.0, alpha: 0.16).setFill()
+ NSBezierPath(ovalIn: rect(560, 74, 520, 520)).fill()
+ NSBezierPath(ovalIn: rect(-120, 520, 440, 440)).fill()
+
+ NSGraphicsContext.restoreGraphicsState()
+ NSGraphicsContext.saveGraphicsState()
+ NSGraphicsContext.current = NSGraphicsContext(bitmapImageRep: rep)
+
+ let shadow = NSShadow()
+ shadow.shadowColor = NSColor.black.withAlphaComponent(0.24)
+ shadow.shadowBlurRadius = 34 * scale
+ shadow.shadowOffset = NSSize(width: 0, height: -10 * scale)
+ shadow.set()
+
+ for (index, item) in [
+ rect(218, 250, 410, 520),
+ rect(306, 214, 410, 520),
+ rect(394, 178, 410, 520)
+ ].enumerated() {
+ let frame = NSBezierPath(roundedRect: item, xRadius: 54 * scale, yRadius: 54 * scale)
+ NSColor(calibratedWhite: 1, alpha: index == 2 ? 0.95 : 0.46).setFill()
+ frame.fill()
+ NSColor(calibratedWhite: 1, alpha: 0.95).setStroke()
+ frame.lineWidth = 10 * scale
+ frame.stroke()
+ }
+
+ shadow.shadowColor = .clear
+ shadow.set()
+
+ let photo = NSBezierPath(roundedRect: rect(430, 214, 338, 436), xRadius: 36 * scale, yRadius: 36 * scale)
+ NSColor(calibratedRed: 0.07, green: 0.16, blue: 0.25, alpha: 1).setFill()
+ photo.fill()
+
+ NSColor(calibratedRed: 0.72, green: 0.92, blue: 1.0, alpha: 1).setFill()
+ NSBezierPath(ovalIn: rect(552, 438, 94, 94)).fill()
+ let body = NSBezierPath(roundedRect: rect(504, 292, 190, 150), xRadius: 82 * scale, yRadius: 82 * scale)
+ body.fill()
+
+ NSColor(calibratedWhite: 1, alpha: 0.96).setStroke()
+ let curve = NSBezierPath()
+ curve.move(to: NSPoint(x: 210 * scale, y: 270 * scale))
+ curve.curve(
+ to: NSPoint(x: 822 * scale, y: 760 * scale),
+ controlPoint1: NSPoint(x: 360 * scale, y: 312 * scale),
+ controlPoint2: NSPoint(x: 618 * scale, y: 620 * scale)
+ )
+ curve.lineWidth = 38 * scale
+ curve.lineCapStyle = .round
+ curve.stroke()
+
+ for point in [(210, 270), (420, 390), (620, 590), (822, 760)] {
+ NSColor(calibratedWhite: 1, alpha: 1).setFill()
+ NSBezierPath(ovalIn: rect(CGFloat(point.0 - 34), CGFloat(point.1 - 34), 68, 68)).fill()
+ NSColor(calibratedRed: 0.08, green: 0.47, blue: 0.78, alpha: 1).setFill()
+ NSBezierPath(ovalIn: rect(CGFloat(point.0 - 18), CGFloat(point.1 - 18), 36, 36)).fill()
+ }
+
+ NSGraphicsContext.restoreGraphicsState()
+
+ guard let data = rep.representation(using: .png, properties: [:]) else {
+ throw NSError(domain: "GrowthLapseIcon", code: 1)
+ }
+ return data
+}
+
+for file in files {
+ let data = try drawIcon(size: file.size)
+ try data.write(to: output.appendingPathComponent(file.name))
+}
diff --git a/dist/source-icon/GrowthLapse-source.png b/dist/source-icon/GrowthLapse-source.png
new file mode 100644
index 0000000..c36b60f
Binary files /dev/null and b/dist/source-icon/GrowthLapse-source.png differ