Skip to content

Instantly share code, notes, and snippets.

@bcardarella
Created September 6, 2025 15:21
Show Gist options
  • Save bcardarella/23b7a5c058922fff3007f07a20fac2cd to your computer and use it in GitHub Desktop.
Save bcardarella/23b7a5c058922fff3007f07a20fac2cd to your computer and use it in GitHub Desktop.

SwiftUI to VML Conversion Rules

Basic Conversion Principles

  1. Element Mapping: SwiftUI view types map 1:1 to VML elements with exact name preservation
  2. Attribute Mapping: SwiftUI initializer parameters become VML element attributes
  3. Modifier Mapping: SwiftUI view modifiers become comma-separated values in the style attribute
  4. Static Content Only: VML represents static UI structure - remove all dynamic bindings, closures, and runtime logic
  5. Template System: ViewBuilder closures convert to template/slot patterns using template attributes

API Modernization

Deprecated APIs to Convert

  • RoundedRectangle().stroke() overlays → Use .clipShape(.rect(cornerRadius:)) with separate overlay templates
  • .cornerRadius().clipShape(.rect(cornerRadius:))
  • .clipShape(RoundedRectangle(cornerRadius:)).clipShape(.rect(cornerRadius:))

Binding and State Handling

  1. Remove Runtime Bindings: Convert .constant(""), $binding, and @State references to static values
  2. Extract Dynamic Values: Dynamic content should use attr() function for client-side substitution
  3. Action Closures: Remove all closure parameters from buttons and interactive elements

Animation and Dynamic Effects

  1. Preserve Animations: All .animation() modifiers should be preserved in VML
  2. Convert Dynamic Value Dependencies: Convert value: UUID() and other dynamic dependencies to static values like value: true
  3. Add Conversion Comments: Include comments near converted animations with:
    • <!-- Original: [exact SwiftUI modifier] -->
    • <!-- Server Note: Replace 'value: true' with dynamic state/trigger during template interpolation -->
  4. Static Effects: Keep 3D transforms, rotation effects, and scale effects as static values

Template/Slot Conversion

ViewBuilder Closures

Convert ViewBuilder closures to template/slot pattern:

SwiftUI:

.overlay(alignment: .center) {
    Circle().fill(.red)
}

VML:

style="overlay(alignment: .center, content: :overlayContent)"
<Circle template="overlayContent" style="fill(.red)"/>

Complex Overlays

For stroke overlays and borders:

SwiftUI:

.overlay(RoundedRectangle(cornerRadius: 12).stroke(.gray, lineWidth: 1))

VML:

style="overlay(content: :strokeOverlay)"
<RoundedRectangle cornerRadius="12" template="strokeOverlay" style="stroke(.gray, lineWidth: 1)"/>

Document Structure

  • Fragment Mode: Unless specifically requested, provide VML fragments without full document wrapper
  • Full Document: When requested, wrap in <!doctype swiftui+vml><vml><body>...</body></vml>

Style Attribute Rules

  1. Spacing: Use , (comma + space) between modifiers and : (colon + space) for labeled arguments
  2. Order Preservation: Maintain the order of modifiers as they appear in SwiftUI chain
  3. Enum Values: Include leading dot for enum values (.leading, .blue, etc.)

Color and Gradient Conversion

  1. Custom Colors: Convert Color(red:, green:, blue:) to .init(red:, green:, blue:) format
  2. Gradient Types: Support all SwiftUI gradient types (LinearGradient, RadialGradient, AngularGradient, MeshGradient)
  3. Array Parameters: Convert Swift arrays to string format for complex parameters like MeshGradient points
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment