mirror of
https://github.com/willfaust/Madeira.git
synced 2026-10-02 00:28:44 +08:00
Library: liquid metal toggle in Settings, Liquid Glass by default
- Settings > Appearance > Liquid metal turns the app's liquid metal on and off at once, fading between it and Liquid Glass both ways; it is off by default (env.MADEIRA_LIQUID_METAL = 1 in madeira.cfg turns it on) and covers the bars, the lens and search field rims and the Desktop button, whose label and fill crossfade. - In dark mode the metal's highlights roll off to 0.8 of white. - The library cards' ambient light is tighter, a little dimmer in dark mode, and a soft knee (AmbientGlow.metal) keeps very bright artwork from glaring. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
79e28f068b
commit
69b2fc0457
@@ -18,6 +18,7 @@
|
||||
A1000910 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = A2000910 /* Assets.xcassets */; };
|
||||
A1000902 /* GlassSkin.swift in Sources */ = {isa = PBXBuildFile; fileRef = A2000902 /* GlassSkin.swift */; };
|
||||
A1000903 /* LiquidMetalSkin.metal in Sources */ = {isa = PBXBuildFile; fileRef = A2000903 /* LiquidMetalSkin.metal */; };
|
||||
A1000904 /* AmbientGlow.metal in Sources */ = {isa = PBXBuildFile; fileRef = A2000904 /* AmbientGlow.metal */; };
|
||||
A1000601 /* SteamOwnedLibrary.swift in Sources */ = {isa = PBXBuildFile; fileRef = A2000601 /* SteamOwnedLibrary.swift */; };
|
||||
A1000602 /* SteamDownloadBackground.swift in Sources */ = {isa = PBXBuildFile; fileRef = A2000602 /* SteamDownloadBackground.swift */; };
|
||||
A1000600 /* SteamInstall.swift in Sources */ = {isa = PBXBuildFile; fileRef = A2000600 /* SteamInstall.swift */; };
|
||||
@@ -131,6 +132,7 @@
|
||||
A2000910 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||
A2000902 /* GlassSkin.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "GlassSkin.swift"; sourceTree = "<group>"; };
|
||||
A2000903 /* LiquidMetalSkin.metal */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.metal; path = "LiquidMetalSkin.metal"; sourceTree = "<group>"; };
|
||||
A2000904 /* AmbientGlow.metal */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.metal; path = "AmbientGlow.metal"; sourceTree = "<group>"; };
|
||||
A2000601 /* SteamOwnedLibrary.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SteamOwnedLibrary.swift"; sourceTree = "<group>"; };
|
||||
A2000602 /* SteamDownloadBackground.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SteamDownloadBackground.swift"; sourceTree = "<group>"; };
|
||||
A2000600 /* SteamInstall.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SteamInstall.swift"; sourceTree = "<group>"; };
|
||||
@@ -312,6 +314,7 @@
|
||||
A2000910 /* Assets.xcassets */,
|
||||
A2000902 /* GlassSkin.swift */,
|
||||
A2000903 /* LiquidMetalSkin.metal */,
|
||||
A2000904 /* AmbientGlow.metal */,
|
||||
A2000601 /* SteamOwnedLibrary.swift */,
|
||||
A2000602 /* SteamDownloadBackground.swift */,
|
||||
A2000600 /* SteamInstall.swift */,
|
||||
@@ -551,6 +554,7 @@
|
||||
A1000900 /* LiquidMetal.metal in Sources */,
|
||||
A1000902 /* GlassSkin.swift in Sources */,
|
||||
A1000903 /* LiquidMetalSkin.metal in Sources */,
|
||||
A1000904 /* AmbientGlow.metal in Sources */,
|
||||
A1000601 /* SteamOwnedLibrary.swift in Sources */,
|
||||
A1000602 /* SteamDownloadBackground.swift in Sources */,
|
||||
A1000600 /* SteamInstall.swift in Sources */,
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
// AmbientGlow.metal — the library's ambient card light (AmbientGlow in Library.swift).
|
||||
//
|
||||
// A SwiftUI [[stitchable]] color shader on the glow layer: a soft knee on its brightest
|
||||
// parts, so a very bright artwork (a neon green cover) throws light as strong as the rest
|
||||
// instead of glaring, while dark and mid tones pass almost unchanged. `knee` is how much
|
||||
// the brightest value comes down (0: off).
|
||||
|
||||
#include <metal_stdlib>
|
||||
#include <SwiftUI/SwiftUI_Metal.h>
|
||||
using namespace metal;
|
||||
|
||||
[[ stitchable ]] half4 ambientKnee(float2 position, half4 color, float knee) {
|
||||
if (color.a <= 0.0h || knee <= 0.0) { return color; }
|
||||
float3 rgb = float3(color.rgb) / float(color.a);
|
||||
rgb -= knee * rgb * rgb;
|
||||
return half4(half3(rgb * float(color.a)), color.a);
|
||||
}
|
||||
@@ -26,10 +26,9 @@ extension ConfigCatalog {
|
||||
ConfigOption(key: "env.MADEIRA_FRONTEND_CONTROLLER", title: "", kind: .bool, defaultValue: "1", category: "App & front end", note: "", choices: [], sources: ["app/Madeira/Library.swift"]),
|
||||
ConfigOption(key: "env.MADEIRA_FRONTEND_DEFAULT_NEW", title: "", kind: .bool, defaultValue: "1", category: "App & front end", note: "Which interface Madeira starts with: the library (the default) or the developer interface. The choice is made in either interface, stored in UserDefaults and read once per run, so a change applies at the next start. Without a stored choi...", choices: [], sources: ["app/Madeira/Library.swift"]),
|
||||
ConfigOption(key: "env.MADEIRA_FRONTEND_KEYBOARD", title: "", kind: .bool, defaultValue: "1", category: "App & front end", note: "MADEIRA_FRONTEND_KEYBOARD=0: the game view's own keyboard instead.", choices: [], sources: ["app/Madeira/Library.swift"]),
|
||||
ConfigOption(key: "env.MADEIRA_GLASS_SKIN", title: "", kind: .bool, defaultValue: "1", category: "App & front end", note: "makes SwiftUI start a morph back to a wider item set from a far wider pill (for about 0.2 s), which stock glass never does; the skin shows it. Placing the skin outside SwiftUI's tree avoids that but gets drawn over dark by the pill's own...", choices: [], sources: ["app/Madeira/GlassSkin.swift"]),
|
||||
ConfigOption(key: "env.MADEIRA_LIBRARY_AMBIENT", title: "", kind: .bool, defaultValue: "1", category: "App & front end", note: "The library's ambient light: a glow behind every grid card that has reported its frame (only the cards the lazy grids have built). MADEIRA_LIBRARY_AMBIENT=0 turns it off.", choices: [], sources: ["app/Madeira/Library.swift"]),
|
||||
ConfigOption(key: "env.MADEIRA_LIBRARY_HIDE_ENDED_DESKTOP", title: "", kind: .bool, defaultValue: "1", category: "App & front end", note: "", choices: [], sources: ["app/Madeira/Library.swift"]),
|
||||
ConfigOption(key: "env.MADEIRA_LIQUID_METAL", title: "", kind: .bool, defaultValue: "1", category: "App & front end", note: "A flowing liquid-chrome fill (LiquidMetal.metal, a SwiftUI color shader): white highlights, silver and navy, rainbow dispersion at the highlights' edges and a raised rim, in a capsule (a rounded box of radius half its height). Animated a...", choices: [], sources: ["app/Madeira/Library.swift"]),
|
||||
ConfigOption(key: "env.MADEIRA_LIQUID_METAL", title: "", kind: .bool, defaultValue: "0", category: "App & front end", note: "Whether the app's liquid metal is on: Settings › Appearance › Liquid metal, kept in madeira.cfg as env.MADEIRA_LIQUID_METAL (off, plain Liquid Glass, unless it is 1). It covers the Desktop button's fill (LiquidMetalFill) and the bars' gl...", choices: [], sources: ["app/Madeira/Library.swift"]),
|
||||
ConfigOption(key: "env.MADEIRA_LOG_VIA_STDERR", title: "", kind: .bool, defaultValue: "1", category: "App & front end", note: "ml359: also persist — jit_log lines (incl. the [no-footprint] verdict) previously reached only the UI view, which dies with the app; pulled logs never contained them.", choices: [], sources: ["app/Madeira/LogStore.swift"]),
|
||||
ConfigOption(key: "env.MADEIRA_ONE_SESSION_PER_RUN", title: "", kind: .bool, defaultValue: "1", category: "App & front end", note: "One Wine session per app run (see LibraryModel.sessionsThisRun).", choices: [], sources: ["app/Madeira/ContentView.swift"]),
|
||||
ConfigOption(key: "env.MADEIRA_PROMOTE", title: "Hold the display at its maximum rate", kind: .bool, defaultValue: "0", category: "App & front end", note: "The opt-in above; read when a session's pacing is applied.", choices: [], sources: ["app/Madeira/FPSOverlay.swift"]),
|
||||
|
||||
@@ -34,11 +34,13 @@ import UIKit
|
||||
/// like a pill, and the lens that lifts out of the selected tab under a finger keeps its
|
||||
/// glass with metal only around its edge, dissolving into the glass toward the middle
|
||||
/// (`rim`). The navigation bar's search field gets the same rim. Everything is found by class name and key-value coding; if any of it is
|
||||
/// missing the glass stays as it is. MADEIRA_GLASS_SKIN=0 turns it off.
|
||||
/// missing the glass stays as it is. Settings › Appearance › Liquid metal (LiquidMetalSetting,
|
||||
/// env.MADEIRA_LIQUID_METAL in madeira.cfg) turns it on and off at once, with the Desktop
|
||||
/// button's liquid metal: off, the app shows plain Liquid Glass.
|
||||
@MainActor
|
||||
final class GlassSkin: NSObject {
|
||||
static let shared = GlassSkin()
|
||||
static let enabled = MadeiraConfig.flag("MADEIRA_GLASS_SKIN")
|
||||
static var enabled: Bool { LiquidMetalSetting.shared.on }
|
||||
private static let groupName = "madeira.glass-skin"
|
||||
|
||||
private var observer: CFRunLoopObserver?
|
||||
@@ -65,8 +67,11 @@ final class GlassSkin: NSObject {
|
||||
let veils: Bool
|
||||
}
|
||||
|
||||
func start() {
|
||||
/// `fadeIn`: liquid metal was just turned on in Settings, so the pills it finds in the
|
||||
/// next moment fade from their glass into metal instead of switching.
|
||||
func start(fadeIn: Bool = false) {
|
||||
guard Self.enabled, observer == nil, Self.privateClassesPresent, preparePipeline() else { return }
|
||||
fadeInUntil = fadeIn ? CACurrentMediaTime() + 0.5 : 0
|
||||
// Core Animation commits in an observer of order 2,000,000; run just before it.
|
||||
observer = CFRunLoopObserverCreateWithHandler(nil, CFRunLoopActivity.beforeWaiting.rawValue | CFRunLoopActivity.exit.rawValue,
|
||||
true, 1_999_999) { _, _ in
|
||||
@@ -82,6 +87,32 @@ final class GlassSkin: NSObject {
|
||||
LogStore.shared.log("[glass-skin] started")
|
||||
}
|
||||
|
||||
/// Takes the skin off every pill (liquid metal turned off in Settings): the metal fades
|
||||
/// out over the system's glass, and nothing more is drawn or attached.
|
||||
func stop() {
|
||||
guard let observer else { return }
|
||||
CFRunLoopRemoveObserver(CFRunLoopGetMain(), observer, .commonModes)
|
||||
self.observer = nil
|
||||
link?.invalidate()
|
||||
link = nil
|
||||
let fading = skins
|
||||
CATransaction.begin()
|
||||
CATransaction.setAnimationDuration(UIAccessibility.isReduceMotionEnabled ? 0.15 : 0.35)
|
||||
CATransaction.setCompletionBlock { MainActor.assumeIsolated { for skin in fading { skin.group.removeFromSuperlayer() } } }
|
||||
for skin in fading {
|
||||
skin.group.opacity = 0
|
||||
if !skin.rim, let backdrop = skin.container?.sublayers?.first(where: { Self.isClass($0, "CABackdropLayer") }) {
|
||||
backdrop.opacity = 1
|
||||
}
|
||||
}
|
||||
CATransaction.commit()
|
||||
skins.removeAll()
|
||||
steadyRects.removeAll()
|
||||
bars.removeAll()
|
||||
veiled = false
|
||||
LogStore.shared.log("[glass-skin] stopped")
|
||||
}
|
||||
|
||||
/// SwiftUI updates a pill's layers during Core Animation's commit itself (its hosting
|
||||
/// view lays out and renders there), after the run-loop observer: when a morph settles
|
||||
/// it swaps the shape's element source and resets the backdrop that way, and one frame
|
||||
@@ -96,9 +127,10 @@ final class GlassSkin: NSObject {
|
||||
return unsafeBitCast(method_getImplementation(method), to: AddCommitHandler.self)
|
||||
}()
|
||||
private var commitHandlerPending = false
|
||||
private var fadeInUntil: CFTimeInterval = 0
|
||||
|
||||
private func attachAgainAfterLayout() {
|
||||
guard !commitHandlerPending, let add = Self.addCommitHandler else { return }
|
||||
guard observer != nil, !commitHandlerPending, let add = Self.addCommitHandler else { return }
|
||||
commitHandlerPending = true
|
||||
add(CATransaction.self, Self.addCommitHandlerSelector, {
|
||||
MainActor.assumeIsolated {
|
||||
@@ -113,6 +145,7 @@ final class GlassSkin: NSObject {
|
||||
}
|
||||
|
||||
private func preparePipeline() -> Bool {
|
||||
if pipeline != nil { return true }
|
||||
guard let device = MTLCreateSystemDefaultDevice(), let library = device.makeDefaultLibrary(),
|
||||
let vertex = library.makeFunction(name: "liquidMetalSkinVertex"),
|
||||
let fragment = library.makeFunction(name: "liquidMetalSkinFragment") else { return false }
|
||||
@@ -130,6 +163,7 @@ final class GlassSkin: NSObject {
|
||||
// MARK: Attaching
|
||||
|
||||
private func attach() {
|
||||
guard observer != nil else { return } // stopped (a commit handler may still fire)
|
||||
// The bars persist; a navigation bar's platter containers do not (opening and
|
||||
// closing a bar button's menu builds a new one), so the glass is looked up under the
|
||||
// bars on every pass (a walk of a few dozen layers) and only the bars are cached.
|
||||
@@ -181,8 +215,13 @@ final class GlassSkin: NSObject {
|
||||
skin.group.opacity = on ? 0 : 1
|
||||
backdrop.opacity = on ? 1 : 0
|
||||
CATransaction.commit()
|
||||
guard !on else { return }
|
||||
for (layer, from, to) in [(skin.group, Float(0), Float(1)), (backdrop, Float(1), Float(0))] {
|
||||
if !on { fadeIn(skin, over: backdrop) }
|
||||
}
|
||||
|
||||
/// The metal fades in over the system's glass (whose backdrop fades out under it).
|
||||
private func fadeIn(_ skin: Skin, over backdrop: CALayer?) {
|
||||
let pairs: [(CALayer, Float, Float)] = [(skin.group, 0, 1)] + (backdrop.map { [($0, Float(1), Float(0))] } ?? [])
|
||||
for (layer, from, to) in pairs {
|
||||
let fade = CABasicAnimation(keyPath: "opacity")
|
||||
fade.fromValue = from
|
||||
fade.toValue = to
|
||||
@@ -358,6 +397,9 @@ final class GlassSkin: NSObject {
|
||||
backdrop.opacity = 0
|
||||
}
|
||||
skins.append(Skin(container: container, source: source, group: group, metal: metal, rim: rim, lens: lens, veils: veils))
|
||||
if CACurrentMediaTime() < fadeInUntil, !(veils && veiled) {
|
||||
fadeIn(skins[skins.count - 1], over: rim ? nil : backdrop)
|
||||
}
|
||||
render(skins[skins.count - 1], light: container.delegate.flatMap { ($0 as? UIView)?.traitCollection.userInterfaceStyle == .light }
|
||||
?? (bars.lazy.compactMap(\.view).first?.traitCollection.userInterfaceStyle == .light))
|
||||
}
|
||||
|
||||
@@ -1419,7 +1419,7 @@ struct AmbientGlow: View {
|
||||
// A soft wash on the wall, and the brighter band just past the edge where the
|
||||
// strip's light lands first.
|
||||
return ZStack {
|
||||
art().scaleEffect(1.11).blur(radius: size.width * 0.085)
|
||||
art().scaleEffect(1.09).blur(radius: size.width * 0.07)
|
||||
art().scaleEffect(1.03).blur(radius: size.width * 0.03).opacity(0.75)
|
||||
}
|
||||
.frame(width: frame.width, height: frame.height)
|
||||
@@ -1432,12 +1432,12 @@ struct AmbientGlow: View {
|
||||
|
||||
var body: some View {
|
||||
// Kept tight, so neighbouring cards' light stays apart in the gaps between them.
|
||||
let spread = size.width * 0.20
|
||||
let spread = size.width * 0.17
|
||||
let frame = CGSize(width: size.width + spread * 2, height: size.height + spread * 2)
|
||||
let movie = AmbientMovie(seed: seed)
|
||||
let dark = scheme == .dark
|
||||
// A game that is not installed throws a fainter, less vivid light.
|
||||
let strength = (dark ? 1.0 : 0.8) * (dimmed ? 0.3 : 1)
|
||||
let strength = (dark ? 0.92 : 0.8) * (dimmed ? 0.3 : 1)
|
||||
let plain = layer(0, false, frame: frame), turned = layer(180, false, frame: frame), mirrored = layer(0, true, frame: frame)
|
||||
TimelineView(.animation(minimumInterval: 1.0 / 30, paused: reduceMotion)) { context in
|
||||
let t = context.date.timeIntervalSinceReferenceDate
|
||||
@@ -1449,6 +1449,9 @@ struct AmbientGlow: View {
|
||||
}
|
||||
.compositingGroup()
|
||||
.hueRotation(.degrees(f.hue))
|
||||
// In the dark the light adds to the page (plusLighter): a very bright artwork's
|
||||
// light is brought down at the top (AmbientGlow.metal) so it does not glare.
|
||||
.colorEffect(ShaderLibrary.ambientKnee(.float(dark ? 0.3 : 0)))
|
||||
.mask { AmbientMovie.mask(f.light) }
|
||||
.mask {
|
||||
let turn = reduceMotion ? 0 : 1.2 * sin(t * 0.12 + Double(seed % 97))
|
||||
@@ -1572,13 +1575,27 @@ enum AmbientArtwork {
|
||||
}
|
||||
}
|
||||
|
||||
/// Whether the app's liquid metal is on: Settings › Appearance › Liquid metal, kept in
|
||||
/// madeira.cfg as env.MADEIRA_LIQUID_METAL (off, plain Liquid Glass, unless it is 1). It
|
||||
/// covers the Desktop button's fill (LiquidMetalFill) and the bars' glass (GlassSkin), and
|
||||
/// applies at once, fading between the two.
|
||||
@MainActor final class LiquidMetalSetting: ObservableObject {
|
||||
static let shared = LiquidMetalSetting()
|
||||
@Published var on = MadeiraConfig.flag("MADEIRA_LIQUID_METAL", fallback: false) {
|
||||
didSet {
|
||||
guard on != oldValue else { return }
|
||||
MadeiraConfig.set("env.MADEIRA_LIQUID_METAL", on ? "1" : nil)
|
||||
if on { GlassSkin.shared.start(fadeIn: true) } else { GlassSkin.shared.stop() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A flowing liquid-chrome fill (LiquidMetal.metal, a SwiftUI color shader): white
|
||||
/// highlights, silver and navy, rainbow dispersion at the highlights' edges and a raised
|
||||
/// rim, in a capsule (a rounded box of radius half its height). Animated at 60 frames a
|
||||
/// second; held still with Reduce Motion. MADEIRA_LIQUID_METAL=0 turns it off, and the
|
||||
/// callers draw their previous fill.
|
||||
/// second; held still with Reduce Motion. Its callers draw their previous fill when liquid
|
||||
/// metal is off (LiquidMetalSetting).
|
||||
struct LiquidMetalFill: View {
|
||||
static let enabled = MadeiraConfig.flag("MADEIRA_LIQUID_METAL")
|
||||
@Environment(\.displayScale) private var displayScale
|
||||
@Environment(\.colorScheme) private var scheme
|
||||
@Environment(\.accessibilityReduceMotion) private var reduceMotion
|
||||
@@ -1764,6 +1781,7 @@ struct LibraryView: View {
|
||||
@ObservedObject private var model = LibraryModel.shared
|
||||
@Environment(\.scenePhase) private var scenePhase
|
||||
@Environment(\.colorScheme) private var colorScheme
|
||||
@ObservedObject private var liquidMetal = LiquidMetalSetting.shared
|
||||
var play: (LibraryEntry) -> Void
|
||||
var enableJIT: () -> Void
|
||||
@ObservedObject private var jitState = LibraryJITState.shared
|
||||
@@ -1908,6 +1926,13 @@ struct LibraryView: View {
|
||||
if SteamSettingsSection.shown, settingsShow("Steam", "Dock", "sign in", "account", "setup") {
|
||||
SteamSettingsSection(open: { settingsSheet = $0 })
|
||||
}
|
||||
if settingsShow("appearance", "liquid metal", "metal", "glass") {
|
||||
Section {
|
||||
Toggle("Liquid metal", isOn: $liquidMetal.on)
|
||||
} header: { Text("Appearance") } footer: {
|
||||
Text("Flowing chrome on the bars and the Desktop button. Off, they use the system's Liquid Glass.")
|
||||
}
|
||||
}
|
||||
if settingsShow("interface", "developer") {
|
||||
Section {
|
||||
Toggle("Use developer interface", isOn: Binding(get: { developerUI }, set: { on in
|
||||
@@ -1955,7 +1980,7 @@ struct LibraryView: View {
|
||||
VStack(alignment: .leading, spacing: 24) {
|
||||
HStack {
|
||||
Button { selected = model.entries.first(where: { $0.desktop == true }) ?? .desktopEntry } label: {
|
||||
if LiquidMetalFill.enabled {
|
||||
if liquidMetal.on {
|
||||
// On the chrome's middle band (dark, or light in light mode), with a soft
|
||||
// halo of the other tone for the moments a highlight passes under it.
|
||||
let light = colorScheme == .light
|
||||
@@ -1970,6 +1995,7 @@ struct LibraryView: View {
|
||||
.background(Color(uiColor: .secondarySystemGroupedBackground), in: Capsule())
|
||||
}
|
||||
}.buttonStyle(.plain)
|
||||
.animation(UIAccessibility.isReduceMotionEnabled ? nil : .easeInOut(duration: 0.4), value: liquidMetal.on)
|
||||
.id(LibraryEntry.desktopID)
|
||||
.overlay(RoundedRectangle(cornerRadius: 22).stroke(focused == LibraryEntry.desktopID && controller.connected ? Color.cyan : .clear, lineWidth: 3))
|
||||
}
|
||||
|
||||
@@ -157,8 +157,8 @@ constant float3 spectrumSum = float3(3.40, 2.75, 2.55);
|
||||
rgb = mix(rgb, float3(1.0), line * 0.75);
|
||||
|
||||
rgb = clamp(rgb, 0.0, 1.0);
|
||||
// In dark mode the highlights roll off to 0.9 (the darks are left alone); in light
|
||||
// In dark mode the highlights roll off to 0.8 (the darks are left alone); in light
|
||||
// mode they stay full white, like the page around them.
|
||||
if (light < 0.5) { rgb -= 0.1 * rgb * rgb; }
|
||||
if (light < 0.5) { rgb -= 0.2 * rgb * rgb; }
|
||||
return half4(half3(rgb * alpha), half(alpha));
|
||||
}
|
||||
|
||||
@@ -158,9 +158,9 @@ fragment half4 liquidMetalSkinFragment(liquidmetalskin::VertexOut in [[stage_in]
|
||||
rgb = navy + (1.0 - navy) * clamp(rgb, 0.0, 1.0);
|
||||
rgb += float3(-0.03, 0.0, 0.07) * (lum * (1.0 - lum) * 4.0);
|
||||
rgb = clamp(rgb, 0.0, 1.0);
|
||||
// In dark mode the highlights roll off to 0.9 (the darks are left alone); in light
|
||||
// In dark mode the highlights roll off to 0.8 (the darks are left alone); in light
|
||||
// mode they stay full white, like the page around them.
|
||||
if (u.light < 0.5) { rgb -= 0.1 * rgb * rgb; }
|
||||
if (u.light < 0.5) { rgb -= 0.2 * rgb * rgb; }
|
||||
|
||||
// The lens: full metal at the edge, gone a rim's width in. The boundary flows with
|
||||
// its own finer, faster folds, so the metal seems to melt into the glass. It grows in
|
||||
|
||||
Reference in New Issue
Block a user