@swiftbrowser/native 0.19.0 → 0.21.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +34 -11
- package/dist/blob.d.ts +85 -11
- package/dist/blob.d.ts.map +1 -1
- package/dist/blob.js +184 -34
- package/dist/blob.js.map +1 -1
- package/dist/bridge.d.ts +33 -2
- package/dist/bridge.d.ts.map +1 -1
- package/dist/bridge.js.map +1 -1
- package/dist/fetch.d.ts +19 -11
- package/dist/fetch.d.ts.map +1 -1
- package/dist/fetch.js +105 -41
- package/dist/fetch.js.map +1 -1
- package/dist/hostRequests.d.ts +3 -1
- package/dist/hostRequests.d.ts.map +1 -1
- package/dist/hostRequests.js +47 -6
- package/dist/hostRequests.js.map +1 -1
- package/dist/index.d.ts +1 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -2
- package/dist/index.js.map +1 -1
- package/dist/runtime.js +1 -1
- package/dist/runtime.js.map +1 -1
- package/dist/webSocket.d.ts.map +1 -1
- package/dist/webSocket.js +13 -1
- package/dist/webSocket.js.map +1 -1
- package/package.json +3 -3
- package/src/blob.ts +215 -34
- package/src/bridge.ts +27 -2
- package/src/fetch.ts +99 -41
- package/src/hostRequests.ts +62 -8
- package/src/index.ts +1 -2
- package/src/runtime.ts +1 -1
- package/src/webSocket.ts +10 -1
- package/swift/Packages/SwiftBrowserDSP/Sources/SwiftBrowserDSP/ProgramNode.swift +122 -19
- package/swift/Packages/SwiftBrowserDSP/Sources/SwiftBrowserDSP/ScopeView.swift +79 -0
- package/swift/Packages/SwiftBrowserDSP/Sources/SwiftBrowserDSPCore/Machine.swift +1247 -209
- package/swift/Packages/SwiftBrowserDSP/Sources/SwiftBrowserDSPCore/Program.swift +314 -19
- package/swift/Packages/SwiftBrowserShader/Package.swift +31 -0
- package/swift/Packages/SwiftBrowserShader/README.md +45 -0
- package/swift/Packages/SwiftBrowserShader/Sources/SwiftBrowserShader/ShaderRenderer.swift +103 -0
- package/swift/Packages/SwiftBrowserShader/Sources/SwiftBrowserShader/ShaderView.swift +168 -0
- package/swift/Packages/SwiftBrowserShader/Sources/SwiftBrowserShaderCore/ShaderProps.swift +120 -0
- package/swift/Sources/SwiftBrowserNative/Host/BodyStream.swift +166 -0
- package/swift/Sources/SwiftBrowserNative/Host/FilesBridge.swift +141 -7
- package/swift/Sources/SwiftBrowserNative/Host/HostBridge.swift +47 -1
- package/swift/Sources/SwiftBrowserNative/Host/HostRequestBridge.swift +98 -29
- package/swift/Sources/SwiftBrowserNative/Runtime/NativeFunctions.swift +1 -1
- package/swift/Sources/SwiftBrowserNative/Runtime/ViewRegistry.swift +57 -0
- package/swift/Sources/SwiftBrowserNative/Views/ElementView.swift +11 -7
- package/swift/Sources/SwiftBrowserNative/Views/Kinds/Drawing.swift +378 -0
- package/swift/Sources/SwiftBrowserNative/Views/Kinds/Navigation.swift +15 -10
- package/swift/Sources/SwiftBrowserNative/Views/Kinds/PopTap.swift +31 -28
- package/swift/Sources/SwiftBrowserNative/Views/StyleModifier.swift +142 -0
- package/swift/Sources/SwiftBrowserProtocol/Drawing.swift +306 -0
- package/swift/Sources/SwiftBrowserProtocol/Props.swift +5 -2
- package/swift/Sources/SwiftBrowserProtocol/RendererEvent.swift +24 -3
- package/swift/Sources/SwiftBrowserProtocol/Style.swift +87 -0
- package/wasm/SwiftBrowserNative.wasm +2 -2
- package/dist/native.d.ts +0 -19
- package/dist/native.d.ts.map +0 -1
- package/dist/native.js +0 -17
- package/dist/native.js.map +0 -1
- package/src/native.ts +0 -35
- package/swift/Sources/SwiftBrowserNative/Runtime/NativeRegistry.swift +0 -53
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
#if canImport(AVFoundation) && canImport(SwiftUI)
|
|
2
|
+
import SwiftBrowserProtocol
|
|
3
|
+
import SwiftUI
|
|
4
|
+
|
|
5
|
+
/// `ScopeView` (@swiftbrowser/dsp): a program node's output as a waveform,
|
|
6
|
+
/// drawn every display frame from what the audio thread keeps for it
|
|
7
|
+
/// (`ScopeTap`), its frames never crossing to the app's JavaScript. The
|
|
8
|
+
/// trace starts at a rising zero crossing, so a steady tone stands still;
|
|
9
|
+
/// it is the page's canvas (packages/dsp/src/scope.ts), step for step.
|
|
10
|
+
struct DSPScopeView: View {
|
|
11
|
+
let token: String
|
|
12
|
+
let color: Color
|
|
13
|
+
let gain: Float
|
|
14
|
+
@State private var reader = ScopeReader()
|
|
15
|
+
|
|
16
|
+
init(props: JSONValue) {
|
|
17
|
+
token = props["view"].string ?? ""
|
|
18
|
+
gain = Float(props["gain"].double ?? 1)
|
|
19
|
+
color = props["color"].string.flatMap(Self.color(hex:)) ?? .accentColor
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
var body: some View {
|
|
23
|
+
TimelineView(.animation) { timeline in
|
|
24
|
+
// The tick's date is the trace's own input: SwiftUI draws a view again only when its inputs change, and
|
|
25
|
+
// a canvas that read nothing from the timeline was drawn once and left.
|
|
26
|
+
ScopeTrace(date: timeline.date, token: token, color: color, gain: gain, reader: reader)
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/// The first rising zero crossing in the first half (scope.ts `traceStart`).
|
|
31
|
+
static func traceStart(_ samples: [Float], _ length: Int) -> Int {
|
|
32
|
+
let last = Swift.max(1, samples.count - length)
|
|
33
|
+
for i in 1..<last where samples[i - 1] < 0 && samples[i] >= 0 { return i }
|
|
34
|
+
return 0
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/// `#rrggbb`.
|
|
38
|
+
static func color(hex: String) -> Color? {
|
|
39
|
+
let digits = hex.hasPrefix("#") ? String(hex.dropFirst()) : hex
|
|
40
|
+
guard digits.count == 6, let value = UInt32(digits, radix: 16) else { return nil }
|
|
41
|
+
return Color(red: Double((value >> 16) & 0xFF) / 255, green: Double((value >> 8) & 0xFF) / 255, blue: Double(value & 0xFF) / 255)
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/// One display frame's trace: what the tap holds at `date`.
|
|
46
|
+
private struct ScopeTrace: View {
|
|
47
|
+
let date: Date
|
|
48
|
+
let token: String
|
|
49
|
+
let color: Color
|
|
50
|
+
let gain: Float
|
|
51
|
+
let reader: ScopeReader
|
|
52
|
+
|
|
53
|
+
var body: some View {
|
|
54
|
+
Canvas { context, size in
|
|
55
|
+
let samples = reader.read(ScopeTaps.tap(token))
|
|
56
|
+
let length = samples.count / 2
|
|
57
|
+
let start = DSPScopeView.traceStart(samples, length)
|
|
58
|
+
var path = Path()
|
|
59
|
+
for i in 0..<length {
|
|
60
|
+
let x = CGFloat(i) / CGFloat(length - 1) * size.width
|
|
61
|
+
let value = Swift.max(-1, Swift.min(1, samples[start + i] * gain))
|
|
62
|
+
let y = size.height / 2 - CGFloat(value) * size.height / 2
|
|
63
|
+
if i == 0 { path.move(to: CGPoint(x: x, y: y)) } else { path.addLine(to: CGPoint(x: x, y: y)) }
|
|
64
|
+
}
|
|
65
|
+
context.stroke(path, with: .color(color), style: StrokeStyle(lineWidth: 1.5, lineJoin: .round))
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/// The view's copy of the newest frames, made again each display frame.
|
|
71
|
+
final class ScopeReader {
|
|
72
|
+
private var samples = [Float](repeating: 0, count: 1024)
|
|
73
|
+
|
|
74
|
+
func read(_ tap: ScopeTap?) -> [Float] {
|
|
75
|
+
tap?.read(into: &samples)
|
|
76
|
+
return samples
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
#endif
|