Makepad Code (editor layout, selection, sidebar, early yield), the EN/ZH Translator with voice, Weather with a generated offline forecast, Amp playing its offline library, and fixes across the other apps and examples. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
489 lines
25 KiB
Text
489 lines
25 KiB
Text
// title: Tube Radio
|
|
// Tube Radio — a 1950s valve radio: a glossy chocolate bakelite cabinet
|
|
// round a woven gold-thread speaker cloth, ivory bakelite control mouldings
|
|
// and push keys, an ivory knob with a gold ring over a printed dial scale,
|
|
// a backlit glass tuning dial with a red needle printed over the picture,
|
|
// two green magic-eye tubes for the level, an oscilloscope-green trace, and
|
|
// the orange glow of the valves bleeding through the cloth from behind.
|
|
use mod.prelude.widgets_internal.*
|
|
|
|
// ---- palette: the dial at night, and the magic eye's green ----
|
|
mod.widgets.hw_palette.screen_bg = #x120a05
|
|
mod.widgets.hw_palette.screen_text = #xf2dcb0
|
|
mod.widgets.hw_palette.screen_muted = #xb8915c
|
|
mod.widgets.hw_palette.accent = #x5cf08a
|
|
mod.widgets.hw_palette.panel_text = #xf0dcb4
|
|
mod.widgets.hw_palette.panel_muted = #xb89a70
|
|
mod.widgets.hw_palette.menu_bg = #x2a160b
|
|
mod.widgets.hw_palette.spill_color = #xff8a3a
|
|
mod.widgets.hw_palette.spill_mono = 0.35
|
|
mod.widgets.hw_palette.spill_knee = 1.2
|
|
mod.widgets.hw_palette.caption_bg = #x1e0e06
|
|
mod.widgets.hw_palette.caption_text = #xe8cf9c
|
|
|
|
// ---- the front: speaker cloth in a glossy bakelite cabinet ----
|
|
mod.widgets.HwChassis.draw_bg.ground = #x93662f
|
|
mod.widgets.HwChassis.draw_bg.light_ink = vec4(1.0, 0.9, 0.75, 1.0)
|
|
mod.widgets.HwChassis.draw_bg.shadow_ink = vec4(0.12, 0.05, 0.02, 1.0)
|
|
mod.widgets.HwChassis.draw_bg.glow_ink = vec4(1.0, 0.55, 0.18, 1.0)
|
|
mod.widgets.HwChassis.draw_bg.spill = vec2(2.6, 0.6)
|
|
mod.widgets.HwChassis.draw_bg.vignette = vec4(0.5, 0.25, 0.30, 1.05)
|
|
mod.widgets.HwChassis.draw_bg.surface = fn(p: vec2, base: vec3) -> vec3 {
|
|
let w = self.world.xy
|
|
// Grille cloth: a basket weave, tan with dark-brown stripes and a gold
|
|
// lurex thread every stripe.
|
|
let u = w / 2.4
|
|
let cell = floor(u)
|
|
let f = fract(u)
|
|
let chk = step(0.5, fract((cell.x + cell.y) * 0.5))
|
|
let th = sin(f.y * 3.14159)
|
|
let tv = sin(f.x * 3.14159)
|
|
let thread = mix(tv, th, chk)
|
|
let slub = self.hw_noise(vec2(w.x * 0.05, cell.y * 0.7)) * 0.5 + self.hw_noise(vec2(cell.x * 0.7, w.y * 0.05)) * 0.5
|
|
let sx = fract(w.x / 56.0)
|
|
let dark_band = (1.0 - smoothstep(0.0, 0.02, abs(sx - 0.62) - 0.035)) + (1.0 - smoothstep(0.0, 0.02, abs(sx - 0.78) - 0.035))
|
|
let lurex = (1.0 - smoothstep(0.0, 0.05, abs(sx - 0.25) + 0.01)) * (1.0 - chk)
|
|
var cloth = mix(base, vec3(0.30, 0.17, 0.08), dark_band * 0.35)
|
|
cloth = cloth * (0.58 + 0.52 * pow(max(thread, 0.0), 0.7)) * (0.93 + 0.14 * slub)
|
|
let spark = step(0.6, self.hw_hash(cell)) * 0.6 + 0.4
|
|
cloth = mix(cloth, vec3(0.95, 0.75, 0.36) * (0.6 + 0.6 * thread) * spark, lurex * 0.6)
|
|
// The valves behind the cloth: a warm orange glow round the screen.
|
|
let uv = p / max(self.rect_size, vec2(1.0, 1.0))
|
|
let g = (uv - vec2(0.5, 0.24)) * vec2(1.5, 2.4)
|
|
let valve = exp(-dot(g, g) * 2.2)
|
|
let h1 = (uv - vec2(0.30, 0.42)) * vec2(5.0, 7.0)
|
|
let h2 = (uv - vec2(0.70, 0.42)) * vec2(5.0, 7.0)
|
|
let hot = exp(-dot(h1, h1)) + exp(-dot(h2, h2))
|
|
cloth = cloth + vec3(1.0, 0.42, 0.08) * (valve * 0.30 + hot * 0.22) * (0.5 + 0.5 * thread)
|
|
// The cabinet: glossy mottled chocolate bakelite with a rolled edge.
|
|
let n1 = self.hw_noise(w * 0.006)
|
|
let n2 = self.hw_noise(w * 0.018 + vec2(n1 * 5.0, n1 * 3.0))
|
|
var bak = mix(vec3(0.16, 0.07, 0.03), vec3(0.34, 0.14, 0.06), smoothstep(0.25, 0.8, n2))
|
|
let e = min(min(p.x, p.y), min(self.rect_size.x - p.x, self.rect_size.y - p.y))
|
|
let fw = 14.0
|
|
let inb = 1.0 - smoothstep(fw - 0.7, fw + 0.7, e)
|
|
let roll = sin(clamp(e / fw, 0.0, 1.0) * 3.14159)
|
|
bak = bak * (0.7 + 0.45 * roll) + vec3(1.0, 0.85, 0.7) * pow(roll, 8.0) * 0.18
|
|
let reveal = (1.0 - smoothstep(0.0, 2.0, abs(e - fw - 1.2))) * 0.7
|
|
var col = mix(cloth, bak, inb)
|
|
col = col * (1.0 - reveal * (1.0 - inb))
|
|
return col
|
|
}
|
|
mod.widgets.Window.pass.clear_color = #x1e0e06
|
|
|
|
// Raised plates: ivory bakelite mouldings, glossy.
|
|
mod.widgets.HwPlate.draw_bg.ground = #xe6d5ae
|
|
mod.widgets.HwPlate.draw_bg.light_ink = vec4(1.0, 0.98, 0.9, 1.0)
|
|
mod.widgets.HwPlate.draw_bg.shadow_ink = vec4(0.22, 0.12, 0.05, 1.0)
|
|
mod.widgets.HwPlate.draw_bg.relief = vec4(4.0, 1.0, 2.5, 0.85)
|
|
mod.widgets.HwPlate.draw_bg.finish = vec4(0.5, 0.35, 0.6, 0.25)
|
|
mod.widgets.HwPlate.draw_bg.shadow = vec4(0.65, 10.0, 1.0, 0.6)
|
|
mod.widgets.HwPlate.draw_bg.glow_ink = vec4(1.0, 0.55, 0.18, 1.0)
|
|
mod.widgets.HwPlate.draw_bg.spill = vec2(4.0, 0.55)
|
|
mod.widgets.HwPlate.radius = 16
|
|
mod.widgets.HwPlate.draw_bg.surface = fn(p: vec2, base: vec3) -> vec3 {
|
|
let w = self.world.xy
|
|
let uv = p / max(self.rect_size, vec2(1.0, 1.0))
|
|
// Ivory: faint cloudy mottling, yellowing toward the lower edge.
|
|
let m = self.hw_noise(w * 0.02) * 0.6 + self.hw_noise(w * 0.07) * 0.4
|
|
var col = base * (0.96 + m * 0.07)
|
|
col = mix(col, col * vec3(0.95, 0.88, 0.74), uv.y * 0.35)
|
|
// A glossy window reflection.
|
|
let t = uv.x + (uv.y - 0.5) * 0.5 - 0.28
|
|
col = col + vec3(1.0, 0.98, 0.92) * exp(-(t * t) / 0.006) * 0.12
|
|
col = col + vec3(1.0, 0.98, 0.92) * exp(-(t - 0.07) * (t - 0.07) / 0.0015) * 0.08
|
|
// A gold pinstripe inlaid round the moulding.
|
|
let e = min(min(p.x, p.y), min(self.rect_size.x - p.x, self.rect_size.y - p.y)) - self.inset
|
|
let pin = 1.0 - smoothstep(0.0, 0.6, abs(e - 7.0) - 0.55)
|
|
col = mix(col, vec3(0.80, 0.58, 0.22) * (1.1 - uv.y * 0.3), pin * 0.9)
|
|
return col
|
|
}
|
|
|
|
// Recessed wells: glossy chocolate bakelite.
|
|
mod.widgets.HwPanel.draw_bg.ground = #x3a1a0b
|
|
mod.widgets.HwPanel.draw_bg.light_ink = vec4(1.0, 0.86, 0.66, 1.0)
|
|
mod.widgets.HwPanel.draw_bg.shadow_ink = vec4(0.04, 0.015, 0.0, 1.0)
|
|
mod.widgets.HwPanel.draw_bg.inner = vec4(0.85, 10.0, 0.0, 0.55)
|
|
mod.widgets.HwPanel.draw_bg.glow_ink = vec4(1.0, 0.55, 0.18, 1.0)
|
|
mod.widgets.HwPanel.draw_bg.spill = vec2(1.8, 0.5)
|
|
mod.widgets.HwPanel.draw_bg.surface = fn(p: vec2, base: vec3) -> vec3 {
|
|
let w = self.world.xy
|
|
let n1 = self.hw_noise(w * 0.006 + vec2(13.0, 7.0))
|
|
let n2 = self.hw_noise(w * 0.02 + vec2(n1 * 5.0, n1 * 3.0))
|
|
var col = mix(base * 0.7, base * vec3(1.35, 1.2, 1.05), smoothstep(0.25, 0.8, n2))
|
|
let uv = p / max(self.rect_size, vec2(1.0, 1.0))
|
|
let t = uv.x + (uv.y - 0.5) * 0.4 - 0.3
|
|
return col + vec3(1.0, 0.85, 0.65) * exp(-(t * t) / 0.01) * 0.06
|
|
}
|
|
|
|
// The screen's surround: deep bakelite, a gold trim, valve glow inside.
|
|
mod.widgets.HwBezel.draw_bg.ground = #x2a1208
|
|
mod.widgets.HwBezel.draw_bg.light_ink = vec4(1.0, 0.85, 0.6, 1.0)
|
|
mod.widgets.HwBezel.draw_bg.shadow_ink = vec4(0.0, 0.0, 0.0, 1.0)
|
|
mod.widgets.HwBezel.draw_bg.inner = vec4(0.95, 14.0, 0.0, 0.55)
|
|
mod.widgets.HwBezel.draw_bg.glow_ink = vec4(1.0, 0.5, 0.15, 1.0)
|
|
mod.widgets.HwBezel.draw_bg.spill = vec2(1.6, 0.4)
|
|
mod.widgets.HwBezel.radius = 18
|
|
mod.widgets.HwBezel.draw_bg.surface = fn(p: vec2, base: vec3) -> vec3 {
|
|
let w = self.world.xy
|
|
let e = min(min(p.x, p.y), min(self.rect_size.x - p.x, self.rect_size.y - p.y)) - self.inset
|
|
let n2 = self.hw_noise(w * 0.02 + vec2(self.hw_noise(w * 0.006) * 5.0, 0.0))
|
|
var col = base * (0.8 + 0.45 * n2)
|
|
// A gold trim ring, bevelled.
|
|
let tr = 1.0 - smoothstep(0.0, 0.8, abs(e - 5.0) - 2.2)
|
|
let tb = clamp((e - 2.8) / 4.4, 0.0, 1.0)
|
|
let gold = vec3(0.86, 0.64, 0.26) * (1.25 - tb * 0.7) + vec3(1.0, 0.92, 0.7) * exp(-(tb - 0.25) * (tb - 0.25) / 0.01) * 0.35
|
|
col = mix(col, gold, tr)
|
|
// The valves' glow, warming the surround toward the glass.
|
|
let g = smoothstep(8.0, 30.0, e)
|
|
let uv = p / max(self.rect_size, vec2(1.0, 1.0))
|
|
col = col + vec3(1.0, 0.40, 0.08) * g * (0.22 + 0.25 * uv.y)
|
|
return col
|
|
}
|
|
|
|
// The glass: a backlit tuning dial printed along the bottom, a red needle,
|
|
// and the valves glowing orange through the corners.
|
|
mod.widgets.HwGlass.draw_bg.glass = vec4(0.0, 0.10, 0.50, 0.0)
|
|
mod.widgets.HwGlass.draw_bg.tint = vec4(1.0, 0.85, 0.6, 0.55)
|
|
mod.widgets.HwGlass.draw_bg.radius = 12.0
|
|
mod.widgets.HwGlass.draw_bg.pixel = fn() {
|
|
let p = self.pos * self.rect_size
|
|
let sz = self.rect_size
|
|
let c = sz * 0.5
|
|
let d = Material.sd_box(p, c, c, self.radius)
|
|
let px = 1.0 / max(self.draw_pass.dpi_factor, 0.5)
|
|
let cov = 1.0 - smoothstep(-px, px, d)
|
|
// Rim darkening and a reflection sheet at the top left.
|
|
let edge = smoothstep(-40.0, 0.0, d) * self.glass.z
|
|
let r = smoothstep(0.55, 0.0, self.pos.y + (self.pos.x - 0.5) * 0.3) * self.glass.y
|
|
var o = vec4(0.0, 0.0, 0.0, edge)
|
|
o = vec4(self.tint.xyz * r, r) + o * (1.0 - r)
|
|
// The valves behind the glass: orange light from the lower corners.
|
|
let g1 = (self.pos - vec2(0.12, 1.02)) * vec2(2.6, 3.2)
|
|
let g2 = (self.pos - vec2(0.88, 1.02)) * vec2(2.6, 3.2)
|
|
let vg = (exp(-dot(g1, g1)) + exp(-dot(g2, g2))) * 0.5 + smoothstep(-26.0, 0.0, d) * 0.35
|
|
let glow = vg * self.tint.w * self.filter_on
|
|
o = vec4(o.xyz + vec3(1.0, 0.42, 0.08) * glow, clamp(o.w + glow * 0.25, 0.0, 1.0))
|
|
return o * cov
|
|
}
|
|
|
|
// The picture lights the cabinet: a strong warm spill with a soft ceiling.
|
|
mod.widgets.HwMilk.light = 3.0
|
|
mod.widgets.HwMilk.light_knee = 0.95
|
|
mod.widgets.HwSpectrum.light = 4.0
|
|
|
|
// ---- the spectrum: an oscilloscope in green phosphor ----
|
|
// Parts by `self.part` (1 well, 2 rule, 3 slot, 4 bar, 5 peak, 6 midline).
|
|
mod.widgets.HwSpectrum.draw_round.pixel = fn() {
|
|
let p = self.pos * self.rect_size
|
|
let sz = self.rect_size
|
|
let px = 1.0 / max(self.draw_pass.dpi_factor, 0.5)
|
|
let phos = vec3(0.22, 1.0, 0.38)
|
|
if self.part > 0.5 && self.part < 1.5 {
|
|
// The well: a phosphor tube above, a lit dial strip, a scope below.
|
|
let c = sz * 0.5
|
|
let d = Material.sd_box(p, c, c, 10.0)
|
|
let cov = 1.0 - smoothstep(-px, px, d)
|
|
let sh = floor((sz.y - 32.0) * 0.68 - 16.0)
|
|
let s0 = 16.0
|
|
let s1 = 16.0 + sh
|
|
let w0 = s1 + 24.0
|
|
let w1 = sz.y - 16.0
|
|
let x0 = 18.0
|
|
let x1 = sz.x - 18.0
|
|
let inx = step(x0, p.x) * step(p.x, x1)
|
|
let ins = inx * step(s0, p.y) * step(p.y, s1)
|
|
let inw = inx * step(w0, p.y) * step(p.y, w1)
|
|
var col = vec3(0.03, 0.018, 0.01)
|
|
// The tube faces: black-green with a faint phosphor haze.
|
|
let hs = (p - vec2(sz.x * 0.5, (s0 + s1) * 0.5)) / vec2(sz.x * 0.6, sh * 0.8)
|
|
let tube = vec3(0.012, 0.03, 0.02) + phos * exp(-dot(hs, hs) * 1.5) * 0.035
|
|
col = mix(col, tube, ins)
|
|
let hw = (p - vec2(sz.x * 0.5, (w0 + w1) * 0.5)) / vec2(sz.x * 0.6, max(w1 - w0, 1.0) * 0.8)
|
|
col = mix(col, vec3(0.012, 0.03, 0.02) + phos * exp(-dot(hw, hw) * 1.5) * 0.05, inw)
|
|
// Graticule: ten columns, dotted rows, a tick every fifth.
|
|
let gxs = (x1 - x0) / 10.0
|
|
let gx = abs(fract((p.x - x0) / gxs + 0.5) - 0.5) * gxs
|
|
let vline = (1.0 - smoothstep(0.0, px, gx - 0.4)) * step(0.5, fract(p.y / 3.0))
|
|
let gys = max(w1 - w0, 1.0) / 4.0
|
|
let gy = abs(fract((p.y - w0) / gys + 0.5) - 0.5) * gys
|
|
let hline = (1.0 - smoothstep(0.0, px, gy - 0.4)) * step(0.5, fract(p.x / 3.0))
|
|
col = col + phos * vline * 0.07 * (ins + inw) + phos * hline * 0.07 * inw
|
|
// A tube's own edge: darker toward its rim.
|
|
let es = min(min(p.x - x0, x1 - p.x), min(p.y - s0, s1 - p.y))
|
|
let ew = min(min(p.x - x0, x1 - p.x), min(p.y - w0, w1 - p.y))
|
|
col = col * (1.0 - (1.0 - smoothstep(0.0, 8.0, es)) * 0.5 * ins - (1.0 - smoothstep(0.0, 8.0, ew)) * 0.5 * inw)
|
|
// The dial strip between them: a warm backlit band, a gold scale.
|
|
let ind = inx * step(s1 + 2.0, p.y) * step(p.y, w0 - 3.0)
|
|
let dy = (p.y - s1 - 2.0) / max(w0 - s1 - 5.0, 1.0)
|
|
let band = vec3(0.13, 0.065, 0.025) + vec3(0.30, 0.13, 0.03) * exp(-(dy - 0.5) * (dy - 0.5) / 0.08)
|
|
col = mix(col, band, ind)
|
|
let tk = abs(fract((p.x - x0) / ((x1 - x0) / 60.0) + 0.5) - 0.5) * (x1 - x0) / 60.0
|
|
let tick = (1.0 - smoothstep(0.0, px, tk - 0.35)) * ind * (1.0 - smoothstep(0.0, px, p.y - s1 - 5.5))
|
|
col = mix(col, vec3(0.95, 0.72, 0.36), tick * 0.8)
|
|
return vec4(col * cov, cov)
|
|
}
|
|
if (self.part > 1.5 && self.part < 2.5) || (self.part > 5.5 && self.part < 6.5) {
|
|
// Level rules and the scope's zero line: dotted phosphor.
|
|
let dot_on = step(0.45, fract(p.x / 4.0))
|
|
let a = 0.22 * dot_on
|
|
return vec4(phos * a, a)
|
|
}
|
|
let yb = sz.y - p.y
|
|
if self.part > 2.5 && self.part < 3.5 {
|
|
// An empty column: unlit phosphor cells.
|
|
let cellv = step(0.3, fract(yb / 4.0))
|
|
let a = cellv * 0.07
|
|
return vec4(phos * a, a)
|
|
}
|
|
if self.part > 4.5 && self.part < 5.5 {
|
|
// Peak marks: white-hot phosphor.
|
|
return vec4(0.85, 1.0, 0.88, 1.0)
|
|
}
|
|
// A lit column: stacked phosphor cells, white-hot at the top.
|
|
let cellv = step(0.28, fract(yb / 4.0))
|
|
let hot = 1.0 - smoothstep(0.0, 10.0, p.y)
|
|
let side = 1.0 - abs(self.pos.x - 0.5) * 0.7
|
|
let col = mix(phos * 0.95, vec3(0.85, 1.0, 0.8), hot * 0.6) * side
|
|
let a = mix(0.25, 1.0, cellv)
|
|
return vec4(col * a, a)
|
|
}
|
|
mod.widgets.HwSpectrum.draw_line.pixel = fn() {
|
|
let p = self.pos * self.rect_size
|
|
let a = self.seg_a
|
|
let b = self.seg_b
|
|
let pa = p - a
|
|
let ba = b - a
|
|
let h = clamp(dot(pa, ba) / max(dot(ba, ba), 0.0001), 0.0, 1.0)
|
|
let d = length(pa - ba * h)
|
|
let core = 1.0 - smoothstep(0.2, 1.0, d)
|
|
let glow = exp(-d * d / 3.0) * 0.5
|
|
let rgb = vec3(0.36, 1.0, 0.55) * glow + vec3(0.8, 1.0, 0.85) * core
|
|
let al = clamp(core + glow, 0.0, 1.0)
|
|
return vec4(rgb, al)
|
|
}
|
|
|
|
// ---- keys: ivory bakelite push keys, brown legends ----
|
|
mod.widgets.HwKey.draw_bg.ground = #xeadcb8
|
|
mod.widgets.HwKey.draw_bg.light_ink = vec4(1.0, 0.98, 0.92, 1.0)
|
|
mod.widgets.HwKey.draw_bg.shadow_ink = vec4(0.20, 0.10, 0.04, 1.0)
|
|
mod.widgets.HwKey.draw_bg.glow_ink = vec4(1.0, 0.55, 0.18, 1.0)
|
|
mod.widgets.HwKey.draw_bg.pattern = vec4(5.0, 1.0, 0.03, 0.0)
|
|
mod.widgets.HwKey.draw_bg.sheen = vec4(0.10, 0.10, 0.25, 0.5)
|
|
mod.widgets.HwKey.draw_bg.relief = vec4(4.0, 1.0, 3.0, 0.9)
|
|
mod.widgets.HwKey.draw_bg.finish = vec4(0.55, 0.4, 0.7, 0.2)
|
|
mod.widgets.HwKey.draw_bg.shadow = vec4(0.70, 6.0, 1.0, 0.65)
|
|
mod.widgets.HwKey.draw_bg.inner = vec4(0.72, 9.0, 0.0, 0.30)
|
|
mod.widgets.HwKey.draw_bg.spill = vec2(3.4, 0.5)
|
|
mod.widgets.HwKey.draw_bg.led = vec4(8.0, 8.0, 2.6, 1.0)
|
|
mod.widgets.HwKey.draw_bg.led_off = vec4(0.35, 0.10, 0.05, 1.0)
|
|
mod.widgets.HwKey.draw_bg.critical_ink = vec4(0.82, 0.60, 0.22, 1.0)
|
|
mod.widgets.HwKey.draw_bg.critical_band = vec4(1.0, 2.5, 100000.0, 0.0)
|
|
mod.widgets.HwKey.emissive = vec4(1.0, 0.5, 0.15, 1.5)
|
|
mod.widgets.HwKey.radius = 9
|
|
mod.widgets.HwKeyButton.draw_text.color = #x3a1c0c
|
|
mod.widgets.HwKeyButton.draw_text.color_hover = #x1e0c04
|
|
mod.widgets.HwKeyButton.draw_text.color_down = #x8a2a10
|
|
mod.widgets.HwKeyButton.draw_text.color_focus = #x3a1c0c
|
|
mod.widgets.HwKeyText.draw_text.color = #x3a1c0c
|
|
mod.widgets.HwKeyText.draw_text.color_hover = #x1e0c04
|
|
mod.widgets.HwKeyText.draw_text.color_down = #x8a2a10
|
|
mod.widgets.HwKeyText.draw_text.color_focus = #x3a1c0c
|
|
|
|
// ---- lamps: pilot-light orange ----
|
|
mod.widgets.HwDash.emissive = vec4(1.0, 0.5, 0.12, 6.0)
|
|
mod.widgets.HwDash.draw_bg.glow_ink = vec4(1.0, 0.55, 0.16, 1.0)
|
|
mod.widgets.HwDash.draw_bg.ground = #x2a1208
|
|
mod.widgets.HwLed.emissive = vec4(1.0, 0.5, 0.12, 3.5)
|
|
mod.widgets.HwLed.draw_bg.glow_ink = vec4(1.0, 0.55, 0.16, 1.0)
|
|
|
|
// ---- knob: fluted ivory, a gold ring, a domed cap over a printed scale ----
|
|
mod.widgets.HwKnobFace.draw_bg.ground = #xe8d8b2
|
|
mod.widgets.HwKnobFace.draw_bg.light_ink = vec4(1.0, 0.98, 0.92, 1.0)
|
|
mod.widgets.HwKnobFace.draw_bg.shadow_ink = vec4(0.18, 0.09, 0.03, 1.0)
|
|
mod.widgets.HwKnobFace.draw_bg.cap_ink = vec4(0.93, 0.86, 0.70, 1.0)
|
|
mod.widgets.HwKnobFace.draw_bg.ptr_ink = vec4(0.30, 0.12, 0.05, 1.0)
|
|
mod.widgets.HwKnobFace.draw_bg.ring = vec4(0.0, 1.3, 2.4, 2.35619)
|
|
mod.widgets.HwKnobFace.draw_bg.led_off = vec4(0.42, 0.28, 0.16, 1.0)
|
|
mod.widgets.HwKnobFace.draw_bg.glow_ink = vec4(1.0, 0.55, 0.16, 1.0)
|
|
mod.widgets.HwKnobFace.draw_bg.shadow = vec4(0.75, 10.0, 1.0, 0.7)
|
|
mod.widgets.HwKnobFace.emissive = vec4(1.0, 0.5, 0.12, 0.6)
|
|
mod.widgets.HwKnobFace.draw_bg.pixel = fn() {
|
|
let p = self.pos * self.rect_size
|
|
let c = self.rect_size * 0.5
|
|
let q = p - c
|
|
let px = 1.0 / max(self.draw_pass.dpi_factor, 0.5)
|
|
let r = min(c.x, c.y) - self.inset
|
|
var o = self.layer(self.surface(p, self.ground.xyz))
|
|
let rq = length(q)
|
|
let ang = atan2(q.x, -q.y)
|
|
let inside = 1.0 - smoothstep(-px, px, rq - r)
|
|
let lt = normalize(self.light.xy + vec2(0.000001, 0.000001))
|
|
let nq = q / max(rq, 0.001)
|
|
var face = o.xyz
|
|
// Fluted skirt: thirty flutes catching the light on one flank.
|
|
let fl = smoothstep(r * 0.80 - px, r * 0.80 + px, rq)
|
|
let fa = ang * 30.0 / 6.28318
|
|
let ff = fract(fa)
|
|
let flank = sin(ff * 6.28318)
|
|
face = face * (1.0 - fl * (0.16 + 0.14 * flank))
|
|
// The gold ring, anisotropic, with dark grooves at its edges.
|
|
let gr = smoothstep(r * 0.66 - px, r * 0.66 + px, rq) * (1.0 - smoothstep(r * 0.80 - px, r * 0.80 + px, rq))
|
|
let aniso = 0.5 + 0.5 * cos((ang - atan2(lt.x, -lt.y)) * 2.0)
|
|
let gold = vec3(0.80, 0.58, 0.22) * (0.7 + 0.55 * aniso) + vec3(1.0, 0.92, 0.7) * pow(aniso, 12.0) * 0.4
|
|
face = mix(face, gold, gr)
|
|
let groove = (1.0 - smoothstep(0.0, 1.0, abs(rq - r * 0.66))) + (1.0 - smoothstep(0.0, 1.0, abs(rq - r * 0.80)))
|
|
face = face * (1.0 - groove * 0.45)
|
|
// The domed ivory cap with a window highlight.
|
|
let capm = 1.0 - smoothstep(r * 0.66 - px, r * 0.66 + px, rq)
|
|
let hl = q / max(r, 1.0) - lt * 0.30
|
|
let spec = exp(-dot(hl, hl) / 0.02) * 0.5
|
|
let capcol = self.cap_ink.xyz * (1.08 - rq / max(r, 1.0) * 0.35 + dot(nq, -lt) * 0.08 * rq / max(r, 1.0)) + vec3(spec, spec, spec)
|
|
face = mix(face, capcol, capm)
|
|
// The pointer: an inlaid brown line on the cap and a gold dot on the skirt.
|
|
let spin = (self.value * 2.0 - 1.0) * self.ring.w
|
|
let dir = vec2(sin(spin), -cos(spin))
|
|
let t = clamp(dot(q, dir), r * 0.16, r * 0.60)
|
|
let pd = length(q - dir * t) - max(r * 0.035, 1.0)
|
|
face = mix(face, self.ptr_ink.xyz, (1.0 - smoothstep(-px, px, pd)) * capm)
|
|
let dd = length(q - dir * r * 0.90) - max(r * 0.05, 1.5)
|
|
face = mix(face, vec3(0.95, 0.75, 0.32), (1.0 - smoothstep(-px, px, dd)))
|
|
o = vec4(face * inside, inside) + o * (1.0 - inside)
|
|
// The printed scale round it: ticks lit by the dial lamp up to the value.
|
|
let n = 11.0
|
|
let a0 = -self.ring.w
|
|
let stepa = (self.ring.w * 2.0) / (n - 1.0)
|
|
let fi = clamp(floor((ang - a0) / stepa + 0.5), 0.0, n - 1.0)
|
|
let ta = a0 + fi * stepa
|
|
let perp = abs(dot(q, vec2(cos(ta), sin(ta))))
|
|
let major = step(0.5, fract(fi * 0.5 + 0.25))
|
|
let r0 = r * 1.10
|
|
let r1 = r * (1.20 + 0.08 * major)
|
|
let tk = (1.0 - smoothstep(-px, px, perp - 0.9 - 0.4 * major)) * step(r0, rq) * step(rq, r1) * step(0.0, dot(q, vec2(sin(ta), -cos(ta))))
|
|
let on = step((fi + 0.5) / n, self.value + 0.02)
|
|
let tcol = mix(vec3(0.36, 0.20, 0.10), vec3(1.0, 0.62, 0.22), on)
|
|
o = vec4(tcol * tk, tk) + o * (1.0 - tk)
|
|
let halo = exp(-perp / 2.5) * step(r0 - 2.0, rq) * step(rq, r1 + 2.0) * on * 0.35 * (1.0 - tk)
|
|
o = o + vec4(vec3(1.0, 0.5, 0.12) * halo, halo) * (1.0 - o.w)
|
|
return vec4(o.xyz + self.dither() * step(0.002, o.w), o.w)
|
|
}
|
|
|
|
// ---- meter: two magic-eye tubes ----
|
|
mod.widgets.HwMeterFace.draw_bg.ground = #x160904
|
|
mod.widgets.HwMeterFace.draw_bg.spill = vec2(0.7, 0.4)
|
|
mod.widgets.HwMeterFace.draw_bg.glow_ink = vec4(0.36, 1.0, 0.55, 1.0)
|
|
mod.widgets.HwMeterFace.draw_bg.light_ink = vec4(1.0, 0.85, 0.6, 1.0)
|
|
mod.widgets.HwMeterFace.draw_bg.shadow_ink = vec4(0.0, 0.0, 0.0, 1.0)
|
|
mod.widgets.HwMeterFace.radius = 12
|
|
mod.widgets.HwMeterFace.emissive = vec4(0.36, 1.0, 0.55, 0.8)
|
|
mod.widgets.HwMeterFace.draw_bg.pixel = fn() {
|
|
let p = self.pos * self.rect_size
|
|
let sz = self.rect_size
|
|
let px = 1.0 / max(self.draw_pass.dpi_factor, 0.5)
|
|
var o = self.layer(self.surface(p, self.ground.xyz))
|
|
let rr = max(min(sz.y * 0.5 - 6.5, sz.x * 0.2), 6.0)
|
|
// Left eye or right eye: whichever is nearer.
|
|
let right = step(sz.x * 0.5, p.x)
|
|
let ce = vec2(mix(sz.x * 0.29, sz.x * 0.71, right), sz.y * 0.5)
|
|
let lv = clamp(mix(self.level.x, self.level.y, right), 0.0, 1.0)
|
|
let q = p - ce
|
|
let rq = length(q)
|
|
let ang = atan2(q.x, -q.y)
|
|
// A soft green glow on the bakelite round the tube.
|
|
let halo = exp(-max(rq - rr, 0.0) / 6.0) * 0.30 * step(rr, rq)
|
|
var col = o.xyz + vec3(0.36, 1.0, 0.55) * halo * o.w
|
|
// Chrome escutcheon ring.
|
|
let ring = smoothstep(rr - px, rr + px, rq) * (1.0 - smoothstep(rr + 3.2 - px, rr + 3.2 + px, rq))
|
|
let lt = vec2(-0.6, -0.8)
|
|
let chrome = vec3(0.55, 0.5, 0.45) + vec3(0.45, 0.42, 0.38) * dot(q / max(rq, 0.001), lt)
|
|
col = mix(col, chrome, ring)
|
|
// The glass: black-green, the fluorescent target round the cap.
|
|
let gl = 1.0 - smoothstep(rr - px, rr + px, rq)
|
|
var eye = vec3(0.01, 0.03, 0.018)
|
|
let tr = rq / rr
|
|
let target = smoothstep(0.30, 0.34, tr) * (1.0 - smoothstep(0.90, 0.95, tr))
|
|
let stri = 0.82 + 0.18 * cos(ang * 36.0)
|
|
var fluo = vec3(0.30, 0.95, 0.50) * (0.35 + 0.75 * tr) * stri
|
|
// The shadow wedge at the top closes as the signal rises.
|
|
let hw = mix(0.95, 0.04, lv)
|
|
let wd = (abs(ang) - hw) * rq
|
|
let lit = smoothstep(-px, px, wd)
|
|
let crest = exp(-max(wd, 0.0) / 1.8) * lit * 0.8
|
|
fluo = fluo * (lit * 0.94 + 0.06) + vec3(0.7, 1.0, 0.75) * crest * 0.6
|
|
eye = eye + fluo * target
|
|
// The cathode shield: a dark cap in the middle.
|
|
let cap = 1.0 - smoothstep(0.30 * rr - px, 0.30 * rr + px, rq)
|
|
eye = mix(eye, vec3(0.05, 0.05, 0.045) + vec3(0.2, 0.2, 0.18) * max(dot(q / max(rq, 0.001), lt), 0.0) * tr * 2.0, cap)
|
|
// A reflection on the dome.
|
|
let rh = (q / rr - vec2(-0.32, -0.38)) * vec2(1.0, 1.6)
|
|
eye = eye + vec3(0.9, 1.0, 0.95) * exp(-dot(rh, rh) / 0.03) * 0.22
|
|
col = mix(col, eye, gl)
|
|
o = vec4(col, max(o.w, max(gl, ring)))
|
|
return vec4(o.xyz + self.dither() * step(0.002, o.w), o.w)
|
|
}
|
|
|
|
// ---- the album well: a record with an oxblood label ----
|
|
mod.widgets.HwArtBlank.draw_bg.ground = #x2a1208
|
|
mod.widgets.HwArtBlank.draw_bg.label_ink = vec4(0.55, 0.10, 0.06, 1.0)
|
|
|
|
// ---- type: brown on ivory, cream on bakelite ----
|
|
mod.widgets.HwCaption.draw_text.color = #x4a2410
|
|
mod.widgets.HwCaption.draw_text.text_style = theme.font_bold{font_size: 8.0}
|
|
mod.widgets.HwTitle.draw_text.color = #x2a1206
|
|
mod.widgets.HwText.draw_text.color = #x2e1608
|
|
mod.widgets.HwPanelTitle.draw_text.color = #xf0dcb4
|
|
mod.widgets.HwPanelText.draw_text.color = #xc8a878
|
|
mod.widgets.HwNavButton.draw_text.color = #xf0dcb4
|
|
mod.widgets.HwDisplayText.draw_text.color = #xffcf8a
|
|
mod.widgets.HwDisplay.draw_bg.ground = #x1a0b04
|
|
mod.widgets.HwDisplay.draw_bg.light_ink = vec4(1.0, 0.85, 0.6, 1.0)
|
|
mod.widgets.HwDisplay.draw_bg.shadow_ink = vec4(0.0, 0.0, 0.0, 1.0)
|
|
mod.widgets.HwDisplay.draw_bg.inner = vec4(0.95, 9.0, 0.0, 0.55)
|
|
mod.widgets.HwDisplay.draw_bg.spill = vec2(1.2, 0.4)
|
|
mod.widgets.HwDisplay.draw_bg.surface = fn(p: vec2, base: vec3) -> vec3 {
|
|
let e = min(min(p.x, p.y), min(self.rect_size.x - p.x, self.rect_size.y - p.y)) - self.inset
|
|
// Dark bakelite with a thin gold trim.
|
|
let tr = 1.0 - smoothstep(0.0, 0.7, abs(e - 2.2) - 1.0)
|
|
return mix(base, vec3(0.78, 0.56, 0.22), tr * 0.8)
|
|
}
|
|
mod.widgets.HwSegmented.draw_bg.well = vec4(0.16, 0.07, 0.03, 1.0)
|
|
mod.widgets.HwSegmented.draw_bg.rim = vec4(0.9, 0.7, 0.35, 0.35)
|
|
mod.widgets.HwSegmented.draw_pill.cap = vec4(0.92, 0.85, 0.68, 0.55)
|
|
mod.widgets.HwSegmented.draw_pill.glow = vec4(1.0, 0.55, 0.16, 1.0)
|
|
mod.widgets.HwSegmented.draw_text.color = #xc8a878
|
|
mod.widgets.HwSegmented.draw_text_selected.color = #x2a1206
|
|
mod.widgets.HwDropDown.draw_bg.well = vec4(0.16, 0.07, 0.03, 1.0)
|
|
mod.widgets.HwDropDown.draw_bg.rim = vec4(0.9, 0.7, 0.35, 0.35)
|
|
mod.widgets.HwDropDown.draw_bg.arrow = vec4(0.95, 0.75, 0.40, 1.0)
|
|
mod.widgets.HwDropDown.draw_text.color = #xf2dcb0
|
|
mod.widgets.HwDropDown.draw_text.color_hover = #xfff0d0
|
|
mod.widgets.HwTextInput.draw_bg.well = vec4(0.10, 0.045, 0.02, 1.0)
|
|
mod.widgets.HwTextInput.draw_bg.rim = vec4(0.9, 0.7, 0.35, 0.30)
|
|
mod.widgets.HwTextInput.draw_text.color = #xf2dcb0
|
|
mod.widgets.HwSplitter.draw_bg.groove = vec4(0.05, 0.02, 0.0, 0.45)
|
|
mod.widgets.HwSplitter.draw_bg.glint = vec4(1.0, 0.85, 0.55, 0.25)
|
|
mod.widgets.HwMenuLayer.draw_bg.border_color = #xc8963c
|
|
|
|
// ---- the picture in this style's colours (THEME COLOURS key; on by default) ----
|
|
mod.widgets.hw_palette.map0 = #x140a04
|
|
mod.widgets.hw_palette.map1 = #x5a3010
|
|
mod.widgets.hw_palette.map2 = #xc07a2c
|
|
mod.widgets.hw_palette.map3 = #xffe2a8
|
|
mod.widgets.hw_palette.map_strength = 0.8
|
|
mod.widgets.hw_palette.map_default = 1.0
|
|
// The screen filter with the THEME COLOURS key: CRT: a bulging tube, scanlines, an RGB mask, bloom.
|
|
mod.widgets.hw_palette.screen_filter = 1.0
|
|
mod.widgets.hw_palette.screen_filter_strength = 0.9
|
|
mod.widgets.hw_palette.screen_cell = 3.0
|
|
mod.widgets.hw_palette.screen_curve = 0.12
|
|
true
|
|
|
|
// ---- EQ (HwEqGraph: the graphic equalizer's era look, STYLE_GUIDE "Graphic EQ") ----
|
|
mod.widgets.HwEqGraph.draw_fader.fader = vec4(2.0, 0.58, 16.0, 4.0)
|
|
mod.widgets.HwEqGraph.draw_fader.cap_ink = vec4(0.27, 0.15, 0.08, 1.0)
|
|
mod.widgets.HwEqGraph.draw_fader.track_ink = vec4(0.03, 0.02, 0.01, 1.0)
|
|
mod.widgets.HwEqGraph.draw_curve.curve = vec4(1.0, 2.0, 9.0, 0.08)
|
|
mod.widgets.HwEqGraph.draw_grid.grid = vec4(1.0, 0.20, 0.30, 0.0)
|
|
mod.widgets.HwEqGraph.draw_spectrum.spectrum = vec4(0.16, 1.0, 0.0, 0.0)
|
|
mod.widgets.HwEqGraph.label_ink = vec4(0.95, 0.86, 0.69, 0.8)
|
|
true
|