// // ARK-OS Splash Animation (Wayland/4K Ready) // // Renders a high-definition, dynamic 4K animation of the ARK atom. // import Foundation // Core parameters (dynamically scaled in drawSwiftSplash) var NUC_R: Double = 28.0 var INNER_R: Double = 120.0 var OUTER_R: Double = 200.0 var ELEC_R: Double = 12.0 var RING_T: Double = 2.0 public var scrW: Int = 1920 public var scrH: Int = 1080 public var bpp: Int = 4 public var lineLen: Int = 1920 * 4 // The Wayland client handle for the splash screen var splashGraphics: ArkGraphics! var renderBuffer: UnsafeMutablePointer! public func emitFrame() { splashGraphics.pan() usleep(16000) // basic ~60fps pacing } func presentScreen() { emitFrame() } func clearScreen(r: UInt8, g: UInt8, b: UInt8) { if renderBuffer == nil { return } let count = scrW * scrH * bpp for i in stride(from: 0, to: count, by: bpp) { renderBuffer[i] = b renderBuffer[i+1] = g renderBuffer[i+2] = r if bpp == 4 { renderBuffer[i+3] = 255 } } } func drawRoundedRect(x: Int, y: Int, w: Int, h: Int, r: UInt8, g: UInt8, b: UInt8, a: UInt8, radius: Int) { if renderBuffer == nil { return } for i in max(0, y).., _ cx: Double, _ cy: Double, _ r: Double, _ r_col: UInt8, _ g_col: UInt8, _ b_col: UInt8, _ alpha: UInt8) { let y0 = max(0, Int(cy - r - 2)) let y1 = min(scrH - 1, Int(cy + r + 2)) let x0 = max(0, Int(cx - r - 2)) let x1 = min(scrW - 1, Int(cx + r + 2)) let rInnerSq = (r - 0.5) * (r - 0.5) let rOuter = r + 0.5 let rOuterSq = rOuter * rOuter let fVal = Double(alpha) / 255.0 let preR = Double(r_col) * fVal let preG = Double(g_col) * fVal let preB = Double(b_col) * fVal for y in y0...y1 { let dy = Double(y) - cy let dySq = dy * dy let rowBase = y * lineLen for x in x0...x1 { let dx = Double(x) - cx let distSq = dx * dx + dySq if distSq < rInnerSq { let off = rowBase + x * bpp let invA = 1.0 - fVal p[off] = UInt8(min(255, preB + Double(p[off]) * invA)) p[off+1] = UInt8(min(255, preG + Double(p[off+1]) * invA)) p[off+2] = UInt8(min(255, preR + Double(p[off+2]) * invA)) if bpp == 4 { p[off+3] = UInt8(min(255, fVal * 255.0 + Double(p[off+3]) * invA)) } } else if distSq < rOuterSq { let dist = sqrt(distSq) let edgeAlpha = fVal * (rOuter - dist) let invA = 1.0 - edgeAlpha let eB = Double(b_col) * edgeAlpha let eG = Double(g_col) * edgeAlpha let eR = Double(r_col) * edgeAlpha let off = rowBase + x * bpp p[off] = UInt8(min(255, eB + Double(p[off]) * invA)) p[off+1] = UInt8(min(255, eG + Double(p[off+1]) * invA)) p[off+2] = UInt8(min(255, eR + Double(p[off+2]) * invA)) if bpp == 4 { p[off+3] = UInt8(min(255, edgeAlpha * 255.0 + Double(p[off+3]) * invA)) } } } } } // Draw ring outline with anti-aliasing func ringAA(_ p: UnsafeMutablePointer, _ cx: Double, _ cy: Double, _ r: Double, _ t: Double, _ val: UInt8) { let scan = r + t + 2 let y0 = max(0, Int(cy - scan)) let y1 = min(scrH - 1, Int(cy + scan)) let x0 = max(0, Int(cx - scan)) let x1 = min(scrW - 1, Int(cx + scan)) let rInMinSq = (r - t - 0.5) * (r - t - 0.5) let rInMaxSq = (r - t + 0.5) * (r - t + 0.5) let rOutMinSq = (r + t - 0.5) * (r + t - 0.5) let rOutMaxSq = (r + t + 0.5) * (r + t + 0.5) let tOuter = t + 0.5 let fVal = Double(val) / 255.0 let c = 255.0 * fVal // We draw white rings for y in y0...y1 { let dy = Double(y) - cy let dySq = dy * dy let rowBase = y * lineLen for x in x0...x1 { let dx = Double(x) - cx let d = dx * dx + dySq if d >= rInMaxSq && d <= rOutMinSq { let off = rowBase + x * bpp let invA = 1.0 - fVal p[off] = UInt8(min(255, c + Double(p[off]) * invA)) p[off+1] = UInt8(min(255, c + Double(p[off+1]) * invA)) p[off+2] = UInt8(min(255, c + Double(p[off+2]) * invA)) if bpp == 4 { p[off+3] = UInt8(min(255, fVal * 255.0 + Double(p[off+3]) * invA)) } } else if (d >= rInMinSq && d < rInMaxSq) || (d > rOutMinSq && d <= rOutMaxSq) { let dist = sqrt(d) let diff = abs(dist - r) let edgeA = fVal * (tOuter - diff) if edgeA > 0 { let invA = 1.0 - edgeA let eC = 255.0 * edgeA let off = rowBase + x * bpp p[off] = UInt8(min(255, eC + Double(p[off]) * invA)) p[off+1] = UInt8(min(255, eC + Double(p[off+1]) * invA)) p[off+2] = UInt8(min(255, eC + Double(p[off+2]) * invA)) if bpp == 4 { p[off+3] = UInt8(min(255, edgeA * 255.0 + Double(p[off+3]) * invA)) } } } } } } // Particle System for ArkText struct ArkTextDot { var x: Double, y: Double var targetX: Double, targetY: Double } func drawSwiftSplash() { print("ui_daemon: Animating Splash Screen in 4K Wayland mode...") // Initialize the Wayland client for the splash screen splashGraphics = ArkGraphics() if !splashGraphics.isConnected { print("ui_daemon: FATAL - Could not connect splash to Wayland server") return } // Extract the raw buffer pointer from ArkGraphics (via memory reflection or a temporary workaround) // Wait, ArkGraphics doesn't expose `buffer` publicly. Let's make it public! renderBuffer = splashGraphics.buffer scrW = splashGraphics.screenWidth scrH = splashGraphics.screenHeight lineLen = scrW * bpp // Scale parameters based on resolution (assuming 1920x1080 baseline) let scale = Double(scrW) / 1920.0 NUC_R = 28.0 * scale INNER_R = 120.0 * scale OUTER_R = 200.0 * scale ELEC_R = 12.0 * scale RING_T = 3.0 * scale let startCx = Double(scrW) / 2.0 let startCy = Double(scrH) / 2.0 // Frame timing via compositor func emitFrame() { presentScreen() } // Phase 1: Spawn & Accelerate (45 frames) for frame in 0..<45 { clearScreen(r: 0, g: 0, b: 0) let t = Double(frame) / 44.0 let easeOut = 1.0 - pow(1.0 - t, 3.0) let curInnerR = INNER_R * easeOut let curOuterR = OUTER_R * easeOut let curElR = max(1.0, ELEC_R * easeOut) let ringBright = UInt8(90.0 * easeOut) // Brighter rings diskAA(renderBuffer, startCx, startCy, NUC_R, 255, 255, 255, 255) if curInnerR > NUC_R { ringAA(renderBuffer, startCx, startCy, curInnerR, RING_T, ringBright) } if curOuterR > NUC_R { ringAA(renderBuffer, startCx, startCy, curOuterR, RING_T, ringBright) } // Quadrupled the rotation speed (ease-in so it smoothly starts spinning) let angle = pow(t, 2.0) * 8.0 for i in 0..<2 { let a = angle + Double(i) * Double.pi diskAA(renderBuffer, startCx + cos(a) * curInnerR, startCy + sin(a) * curInnerR, curElR, 255, 255, 255, 255) } for i in 0..<2 { let a = -angle * 0.7 + Double(i) * Double.pi diskAA(renderBuffer, startCx + cos(a) * curOuterR, startCy + sin(a) * curOuterR, curElR, 255, 255, 255, 255) } emitFrame() } // Phase 2: Fast Stable Orbiting (120 frames for multiple full rotations) for frame in 0..<120 { clearScreen(r: 0, g: 0, b: 0) // 8.0 rads from previous + 0.3 rads per frame = fast spinning! let angle = 8.0 + Double(frame) * 0.3 diskAA(renderBuffer, startCx, startCy, NUC_R, 255, 255, 255, 255) ringAA(renderBuffer, startCx, startCy, INNER_R, RING_T, 90) ringAA(renderBuffer, startCx, startCy, OUTER_R, RING_T, 90) for i in 0..<2 { let a = angle + Double(i) * Double.pi diskAA(renderBuffer, startCx + cos(a) * INNER_R, startCy + sin(a) * INNER_R, ELEC_R, 255, 255, 255, 255) } for i in 0..<2 { let a = -angle * 0.7 + Double(i) * Double.pi diskAA(renderBuffer, startCx + cos(a) * OUTER_R, startCy + sin(a) * OUTER_R, ELEC_R, 255, 255, 255, 255) } emitFrame() } // Phase 3: Deceleration (60 frames) let baseAngle = 8.0 + (120.0 * 0.3) var currentSpeed = 0.3 var currentAngle = baseAngle for _ in 0..<60 { clearScreen(r: 0, g: 0, b: 0) currentSpeed *= 0.93 // Slower decay for smoother stop currentAngle += currentSpeed diskAA(renderBuffer, startCx, startCy, NUC_R, 255, 255, 255, 255) ringAA(renderBuffer, startCx, startCy, INNER_R, RING_T, 90) ringAA(renderBuffer, startCx, startCy, OUTER_R, RING_T, 90) for i in 0..<2 { let a = currentAngle + Double(i) * Double.pi diskAA(renderBuffer, startCx + cos(a) * INNER_R, startCy + sin(a) * INNER_R, ELEC_R, 255, 255, 255, 255) } for i in 0..<2 { let a = -currentAngle * 0.7 + Double(i) * Double.pi diskAA(renderBuffer, startCx + cos(a) * OUTER_R, startCy + sin(a) * OUTER_R, ELEC_R, 255, 255, 255, 255) } emitFrame() } // Phase 4: Slide to Top-Left (40 frames) let endAngleInner = currentAngle let endAngleOuter = -currentAngle * 0.7 let targetCx = 180.0 * scale let targetCy = 180.0 * scale for frame in 0..<40 { clearScreen(r: 0, g: 0, b: 0) let t = Double(frame) / 39.0 let easeOut = 1.0 - pow(1.0 - t, 3.0) let cx = startCx + (targetCx - startCx) * easeOut let cy = startCy + (targetCy - startCy) * easeOut diskAA(renderBuffer, cx, cy, NUC_R, 255, 255, 255, 255) ringAA(renderBuffer, cx, cy, INNER_R, RING_T, 90) ringAA(renderBuffer, cx, cy, OUTER_R, RING_T, 90) for i in 0..<2 { let a = endAngleInner + Double(i) * Double.pi diskAA(renderBuffer, cx + cos(a) * INNER_R, cy + sin(a) * INNER_R, ELEC_R, 255, 255, 255, 255) } for i in 0..<2 { let a = endAngleOuter + Double(i) * Double.pi diskAA(renderBuffer, cx + cos(a) * OUTER_R, cy + sin(a) * OUTER_R, ELEC_R, 255, 255, 255, 255) } emitFrame() } // Phase 5: Electron Glows Blue (30 frames) let glowingIndex = 0 let glowingAngle = endAngleInner + Double(glowingIndex) * Double.pi let glowEx = targetCx + cos(glowingAngle) * INNER_R let glowEy = targetCy + sin(glowingAngle) * INNER_R for frame in 0..<30 { clearScreen(r: 0, g: 0, b: 0) let t = Double(frame) / 29.0 diskAA(renderBuffer, targetCx, targetCy, NUC_R, 255, 255, 255, 255) ringAA(renderBuffer, targetCx, targetCy, INNER_R, RING_T, 90) ringAA(renderBuffer, targetCx, targetCy, OUTER_R, RING_T, 90) // Non-glowing electron let a2 = endAngleInner + Double.pi diskAA(renderBuffer, targetCx + cos(a2) * INNER_R, targetCy + sin(a2) * INNER_R, ELEC_R, 255, 255, 255, 255) for i in 0..<2 { let a = endAngleOuter + Double(i) * Double.pi diskAA(renderBuffer, targetCx + cos(a) * OUTER_R, targetCy + sin(a) * OUTER_R, ELEC_R, 255, 255, 255, 255) } // Glowing electron let glowRad = 20.0 * scale * t if glowRad > 0 { // Blue glow aura diskAA(renderBuffer, glowEx, glowEy, ELEC_R + glowRad, 30, 144, 255, UInt8(180.0 * t)) } // Core changes to bright blue let coreR = UInt8(255 - 200 * t) let coreG = UInt8(255 - 100 * t) diskAA(renderBuffer, glowEx, glowEy, ELEC_R, coreR, coreG, 255, 255) emitFrame() } // Phase 6: Drop and Roll to "Get Started" (50 frames) let btnW = 300.0 * scale let btnH = 80.0 * scale let btnX = Double(scrW) / 2.0 - btnW / 2.0 let btnY = Double(scrH) - 200.0 * scale - btnH for frame in 0..<50 { clearScreen(r: 0, g: 0, b: 0) let t = Double(frame) / 49.0 let easeIn = t * t // Draw static atom diskAA(renderBuffer, targetCx, targetCy, NUC_R, 255, 255, 255, 255) ringAA(renderBuffer, targetCx, targetCy, INNER_R, RING_T, 90) ringAA(renderBuffer, targetCx, targetCy, OUTER_R, RING_T, 90) let a2 = endAngleInner + Double.pi diskAA(renderBuffer, targetCx + cos(a2) * INNER_R, targetCy + sin(a2) * INNER_R, ELEC_R, 255, 255, 255, 255) for i in 0..<2 { let a = endAngleOuter + Double(i) * Double.pi diskAA(renderBuffer, targetCx + cos(a) * OUTER_R, targetCy + sin(a) * OUTER_R, ELEC_R, 255, 255, 255, 255) } // Falling & morphing electron let curEx = glowEx + (btnX + btnW/2 - glowEx) * t // Bounce effect for Y let bounceT = abs(sin(t * Double.pi * 1.5)) * (1.0 - t) let curEy = glowEy + (btnY + btnH/2 - glowEy) * easeIn - (100.0 * scale * bounceT) // Morph from circle to rounded rect let curW = (ELEC_R * 2.0) + (btnW - (ELEC_R * 2.0)) * t let curH = (ELEC_R * 2.0) + (btnH - (ELEC_R * 2.0)) * t let curRad = Int((ELEC_R) + (Double(btnH/2) - ELEC_R) * t) drawRoundedRect(x: Int(curEx - curW/2), y: Int(curEy - curH/2), w: Int(curW), h: Int(curH), r: 30, g: 144, b: 255, a: 255, radius: curRad) emitFrame() } // Phase 7: White Dots Assemble "Welcome to ARK-OS!" (60 frames) // Create text points by sampling a grid inside the text area var dots: [ArkTextDot] = [] let textW = 800.0 * scale let textH = 100.0 * scale let textX = Double(scrW)/2.0 - textW/2.0 let textY = Double(scrH)/2.0 - textH/2.0 // Create some random dots that represent "text" for _ in 0..<2000 { let ty = Double.random(in: 0.. 0.2 { let spawnX = (Double.random(in: 0...1) > 0.5) ? -200.0 : Double(scrW) + 200.0 let spawnY = Double.random(in: 0..= 0 && px < scrW && py >= 0 && py < scrH { let off = py * lineLen + px * bpp renderBuffer[off] = 255 renderBuffer[off+1] = 255 renderBuffer[off+2] = 255 if bpp == 4 { renderBuffer[off+3] = 255 } // Make dots slightly larger for 4K if scale > 1.5 { if px+1 < scrW { renderBuffer[off+bpp] = 255; renderBuffer[off+bpp+1] = 255; renderBuffer[off+bpp+2] = 255; if bpp == 4 { renderBuffer[off+bpp+3] = 255 } } if py+1 < scrH { let off2 = (py+1) * lineLen + px * bpp renderBuffer[off2] = 255; renderBuffer[off2+1] = 255; renderBuffer[off2+2] = 255; if bpp == 4 { renderBuffer[off2+3] = 255 } } } } } emitFrame() } }