// Generated by build-voxels.mjs --swift from sites/apps/assets/voxel-models.json. Source SHA-256 1f9bcb3c979d4cd799d668e5e12429de8379a1f731483dedd731d180226ba282. Do not edit. import Foundation /// Face palette key of one voxel; colors resolve through AIMMiniAppTokens in AIMVoxelView.swift. public enum AIMVoxelColor: String, CaseIterable { case ink, mid, light, red } /// One finite reaction to a click, the same spec as aim-voxel.js: flash (cells take a colour for hold seconds and return), /// mirror (the model mirrors on an axis and stays), cycle (the signal steps to the next cell of the list and stays). public enum AIMVoxelGesture { case flash(cells: [(x: Int, y: Int, z: Int)], color: AIMVoxelColor, hold: Double) case mirror(axis: String) case cycle(cells: [(x: Int, y: Int, z: Int)], color: AIMVoxelColor) } /// Shared motion constants, seconds; web uses the same values in milliseconds. public enum AIMVoxelMotion { public static let assemble: Double = 0.7 public static let scatter: Double = 0.25 public static let reassemble: Double = 0.55 public static let hover: Double = 0.16 public static let hoverLift: Double = 2 public static let steps = (min: 6, max: 8) } /// One character: a light figure of at most 200 voxels in a 12×12×12 grid plus one gesture. public struct AIMVoxelModel { public let name: String public let label: String public let note: String public let voxels: [(x: Int, y: Int, z: Int, c: AIMVoxelColor)] public let gesture: AIMVoxelGesture? public init(name: String, label: String, note: String, voxels: [(x: Int, y: Int, z: Int, c: AIMVoxelColor)], gesture: AIMVoxelGesture? = nil) { self.name = name; self.label = label; self.note = note; self.voxels = voxels; self.gesture = gesture } public var count: Int { voxels.count } /// Positions of the red signal voxels (one for relay, aside, calendar; a 2×2 block for family and prism). public var signals: [(x: Int, y: Int, z: Int)] { voxels.filter { $0.c == .red }.map { ($0.x, $0.y, $0.z) } } } public enum AIMVoxelModels { public static let version = "2026-09-14" public static let sourceSHA256 = "1f9bcb3c979d4cd799d668e5e12429de8379a1f731483dedd731d180226ba282" public static let grid = (x: 12, y: 12, z: 12) public static let unit: Double = 10 public static let projection = "screen = (ox + (x - y) * u, oy + (x + y) * 0.48 * u - z * u)" /// ai mindset · family profile · 122 voxels public static let family = AIMVoxelModel(name: "family", label: "ai mindset · family profile", note: "head circle, vertical slit with stem, red eye, crescent smile – from aim-logo-light.png", voxels: [ (2, 5, 4, .ink), (3, 5, 3, .ink), (2, 5, 5, .ink), (3, 5, 4, .ink), (2, 6, 4, .ink), (4, 5, 3, .ink), (3, 6, 3, .ink), (5, 5, 2, .ink), (7, 5, 0, .ink), (2, 5, 6, .ink), (3, 5, 5, .ink), (2, 6, 5, .ink), (4, 5, 4, .ink), (3, 6, 4, .ink), (5, 5, 3, .ink), (4, 6, 3, .ink), (5, 6, 2, .ink), (7, 5, 1, .ink), (7, 6, 0, .ink), (2, 5, 7, .ink), (3, 5, 6, .red), (2, 6, 6, .ink), (4, 5, 5, .ink), (3, 6, 5, .ink), (5, 5, 4, .ink), (4, 6, 4, .ink), (5, 6, 3, .ink), (7, 5, 2, .ink), (7, 6, 1, .ink), (2, 5, 8, .ink), (3, 5, 7, .red), (2, 6, 7, .ink), (4, 5, 6, .red), (3, 6, 6, .red), (5, 5, 5, .ink), (4, 6, 5, .ink), (5, 6, 4, .ink), (7, 5, 3, .ink), (7, 6, 2, .ink), (2, 5, 9, .ink), (3, 5, 8, .ink), (2, 6, 8, .ink), (4, 5, 7, .red), (3, 6, 7, .red), (5, 5, 6, .ink), (4, 6, 6, .red), (5, 6, 5, .ink), (7, 5, 4, .ink), (8, 5, 3, .ink), (7, 6, 3, .ink), (3, 5, 9, .ink), (2, 6, 9, .ink), (4, 5, 8, .ink), (3, 6, 8, .ink), (5, 5, 7, .ink), (4, 6, 7, .red), (5, 6, 6, .ink), (7, 5, 5, .ink), (8, 5, 4, .ink), (7, 6, 4, .ink), (9, 5, 3, .ink), (8, 6, 3, .ink), (3, 5, 10, .ink), (4, 5, 9, .ink), (3, 6, 9, .ink), (5, 5, 8, .ink), (4, 6, 8, .ink), (5, 6, 7, .ink), (7, 5, 6, .ink), (7, 6, 5, .ink), (9, 5, 4, .ink), (8, 6, 4, .ink), (9, 6, 3, .ink), (4, 5, 10, .ink), (3, 6, 10, .ink), (5, 5, 9, .ink), (4, 6, 9, .ink), (5, 6, 8, .ink), (7, 5, 7, .ink), (7, 6, 6, .ink), (10, 5, 4, .ink), (9, 6, 4, .ink), (5, 5, 10, .ink), (4, 6, 10, .ink), (5, 6, 9, .ink), (7, 5, 8, .ink), (8, 5, 7, .ink), (7, 6, 7, .ink), (10, 5, 5, .ink), (10, 6, 4, .ink), (5, 5, 11, .ink), (5, 6, 10, .ink), (7, 5, 9, .ink), (8, 5, 8, .ink), (7, 6, 8, .ink), (9, 5, 7, .ink), (8, 6, 7, .ink), (10, 6, 5, .ink), (5, 6, 11, .ink), (7, 5, 10, .ink), (8, 5, 9, .ink), (7, 6, 9, .ink), (9, 5, 8, .ink), (8, 6, 8, .ink), (10, 5, 7, .ink), (9, 6, 7, .ink), (7, 5, 11, .ink), (8, 5, 10, .ink), (7, 6, 10, .ink), (9, 5, 9, .ink), (8, 6, 9, .ink), (10, 5, 8, .ink), (9, 6, 8, .ink), (10, 6, 7, .ink), (7, 6, 11, .ink), (9, 5, 10, .ink), (8, 6, 10, .ink), (10, 5, 9, .ink), (9, 6, 9, .ink), (10, 6, 8, .ink), (9, 6, 10, .ink), (10, 6, 9, .ink) ], gesture: .flash(cells: [(3, 5, 6), (3, 5, 7), (4, 5, 6), (4, 5, 7), (3, 6, 6), (3, 6, 7), (4, 6, 6), (4, 6, 7)], color: .light, hold: 0.14)) /// language relay · 52 voxels public static let relay = AIMVoxelModel(name: "relay", label: "language relay", note: "two opposite arrows, red tip on the outgoing one", voxels: [ (1, 5, 2, .ink), (2, 5, 1, .ink), (3, 5, 0, .ink), (1, 6, 2, .ink), (2, 5, 2, .ink), (2, 6, 1, .ink), (3, 6, 0, .ink), (2, 5, 3, .ink), (2, 6, 2, .ink), (3, 5, 2, .ink), (2, 6, 3, .ink), (3, 6, 2, .ink), (4, 5, 2, .ink), (3, 5, 4, .ink), (4, 6, 2, .ink), (5, 5, 2, .ink), (1, 5, 7, .ink), (3, 6, 4, .ink), (5, 6, 2, .ink), (6, 5, 2, .ink), (1, 6, 7, .ink), (2, 5, 7, .ink), (6, 6, 2, .ink), (7, 5, 2, .ink), (2, 6, 7, .ink), (3, 5, 7, .ink), (7, 6, 2, .ink), (8, 5, 2, .ink), (3, 6, 7, .ink), (4, 5, 7, .ink), (8, 6, 2, .ink), (9, 5, 2, .ink), (4, 6, 7, .ink), (5, 5, 7, .ink), (9, 6, 2, .ink), (5, 6, 7, .ink), (6, 5, 7, .ink), (8, 5, 5, .ink), (6, 6, 7, .ink), (7, 5, 7, .ink), (8, 6, 5, .ink), (7, 6, 7, .ink), (8, 5, 7, .ink), (9, 5, 6, .ink), (8, 6, 7, .ink), (9, 5, 7, .ink), (9, 6, 6, .ink), (8, 5, 9, .ink), (9, 5, 8, .ink), (9, 6, 7, .red), (8, 6, 9, .ink), (9, 6, 8, .ink) ], gesture: .mirror(axis: "x")) /// aside tweaks · 182 voxels public static let aside = AIMVoxelModel(name: "aside", label: "aside tweaks", note: "panel: light plate, ink sidebar, three rows, red cursor", voxels: [ (0, 4, 0, .light), (0, 4, 1, .light), (1, 4, 0, .light), (0, 4, 2, .light), (1, 4, 1, .light), (2, 4, 0, .light), (0, 4, 3, .light), (1, 4, 2, .light), (2, 4, 1, .light), (1, 5, 1, .ink), (3, 4, 0, .light), (0, 4, 4, .light), (1, 4, 3, .light), (2, 4, 2, .light), (1, 5, 2, .ink), (3, 4, 1, .light), (2, 5, 1, .ink), (4, 4, 0, .light), (0, 4, 5, .light), (1, 4, 4, .light), (2, 4, 3, .light), (1, 5, 3, .ink), (3, 4, 2, .light), (2, 5, 2, .ink), (4, 4, 1, .light), (5, 4, 0, .light), (0, 4, 6, .light), (1, 4, 5, .light), (2, 4, 4, .light), (1, 5, 4, .ink), (3, 4, 3, .light), (2, 5, 3, .ink), (4, 4, 2, .light), (5, 4, 1, .light), (6, 4, 0, .light), (0, 4, 7, .light), (1, 4, 6, .light), (2, 4, 5, .light), (1, 5, 5, .ink), (3, 4, 4, .light), (2, 5, 4, .ink), (4, 4, 3, .light), (5, 4, 2, .light), (6, 4, 1, .light), (7, 4, 0, .light), (0, 4, 8, .light), (1, 4, 7, .light), (2, 4, 6, .light), (1, 5, 6, .ink), (3, 4, 5, .light), (2, 5, 5, .ink), (4, 4, 4, .light), (5, 4, 3, .light), (6, 4, 2, .light), (7, 4, 1, .light), (8, 4, 0, .light), (0, 4, 9, .light), (1, 4, 8, .light), (2, 4, 7, .light), (1, 5, 7, .ink), (3, 4, 6, .light), (2, 5, 6, .ink), (4, 4, 5, .light), (5, 4, 4, .light), (4, 5, 4, .mid), (6, 4, 3, .light), (7, 4, 2, .light), (8, 4, 1, .light), (9, 4, 0, .light), (0, 4, 10, .light), (1, 4, 9, .light), (2, 4, 8, .light), (1, 5, 8, .ink), (3, 4, 7, .light), (2, 5, 7, .ink), (4, 4, 6, .light), (5, 4, 5, .light), (6, 4, 4, .light), (5, 5, 4, .mid), (7, 4, 3, .light), (8, 4, 2, .light), (9, 4, 1, .light), (10, 4, 0, .light), (0, 4, 11, .light), (1, 4, 10, .light), (2, 4, 9, .light), (1, 5, 9, .ink), (3, 4, 8, .light), (2, 5, 8, .ink), (4, 4, 7, .light), (5, 4, 6, .light), (4, 5, 6, .mid), (6, 4, 5, .light), (7, 4, 4, .light), (6, 5, 4, .mid), (8, 4, 3, .light), (9, 4, 2, .light), (10, 4, 1, .light), (11, 4, 0, .light), (1, 4, 11, .light), (2, 4, 10, .light), (1, 5, 10, .ink), (3, 4, 9, .light), (2, 5, 9, .ink), (4, 4, 8, .light), (5, 4, 7, .light), (6, 4, 6, .light), (5, 5, 6, .mid), (7, 4, 5, .light), (8, 4, 4, .light), (7, 5, 4, .mid), (9, 4, 3, .light), (10, 4, 2, .light), (11, 4, 1, .light), (2, 4, 11, .light), (3, 4, 10, .light), (2, 5, 10, .ink), (4, 4, 9, .light), (5, 4, 8, .light), (4, 5, 8, .red), (6, 4, 7, .light), (7, 4, 6, .light), (6, 5, 6, .mid), (8, 4, 5, .light), (9, 4, 4, .light), (8, 5, 4, .mid), (10, 4, 3, .light), (11, 4, 2, .light), (3, 4, 11, .light), (4, 4, 10, .light), (5, 4, 9, .light), (6, 4, 8, .light), (5, 5, 8, .mid), (7, 4, 7, .light), (8, 4, 6, .light), (7, 5, 6, .mid), (9, 4, 5, .light), (10, 4, 4, .light), (9, 5, 4, .mid), (11, 4, 3, .light), (4, 4, 11, .light), (5, 4, 10, .light), (6, 4, 9, .light), (7, 4, 8, .light), (6, 5, 8, .mid), (8, 4, 7, .light), (9, 4, 6, .light), (8, 5, 6, .mid), (10, 4, 5, .light), (11, 4, 4, .light), (5, 4, 11, .light), (6, 4, 10, .light), (7, 4, 9, .light), (8, 4, 8, .light), (7, 5, 8, .mid), (9, 4, 7, .light), (10, 4, 6, .light), (11, 4, 5, .light), (6, 4, 11, .light), (7, 4, 10, .light), (8, 4, 9, .light), (9, 4, 8, .light), (8, 5, 8, .mid), (10, 4, 7, .light), (11, 4, 6, .light), (7, 4, 11, .light), (8, 4, 10, .light), (9, 4, 9, .light), (10, 4, 8, .light), (9, 5, 8, .mid), (11, 4, 7, .light), (8, 4, 11, .light), (9, 4, 10, .light), (10, 4, 9, .light), (11, 4, 8, .light), (10, 5, 8, .mid), (9, 4, 11, .light), (10, 4, 10, .light), (11, 4, 9, .light), (10, 4, 11, .light), (11, 4, 10, .light), (11, 4, 11, .light) ], gesture: .cycle(cells: [(4, 5, 8), (4, 5, 6), (4, 5, 4)], color: .red)) /// mem prism · 184 voxels public static let prism = AIMVoxelModel(name: "prism", label: "mem prism", note: "hex-plan crystal column, stepped tip, red core on the front face", voxels: [ (3, 5, 0, .ink), (4, 4, 0, .ink), (5, 3, 0, .ink), (3, 5, 1, .ink), (4, 4, 1, .ink), (5, 3, 1, .ink), (3, 6, 0, .ink), (4, 5, 0, .ink), (5, 4, 0, .ink), (6, 3, 0, .ink), (3, 5, 2, .ink), (4, 4, 2, .ink), (5, 3, 2, .ink), (3, 6, 1, .ink), (4, 5, 1, .ink), (5, 4, 1, .ink), (6, 3, 1, .ink), (4, 6, 0, .ink), (5, 5, 0, .ink), (6, 4, 0, .ink), (3, 5, 3, .ink), (4, 4, 3, .ink), (5, 3, 3, .ink), (3, 6, 2, .ink), (4, 5, 2, .ink), (5, 4, 2, .ink), (6, 3, 2, .ink), (4, 6, 1, .ink), (5, 5, 1, .ink), (6, 4, 1, .ink), (4, 7, 0, .ink), (5, 6, 0, .ink), (6, 5, 0, .ink), (7, 4, 0, .ink), (3, 5, 4, .ink), (4, 4, 4, .ink), (5, 3, 4, .ink), (3, 6, 3, .ink), (4, 5, 3, .ink), (5, 4, 3, .ink), (6, 3, 3, .ink), (4, 6, 2, .ink), (5, 5, 2, .ink), (6, 4, 2, .ink), (4, 7, 1, .ink), (5, 6, 1, .ink), (6, 5, 1, .ink), (7, 4, 1, .ink), (5, 7, 0, .ink), (6, 6, 0, .ink), (7, 5, 0, .ink), (3, 5, 5, .mid), (4, 4, 5, .mid), (5, 3, 5, .mid), (3, 6, 4, .ink), (4, 5, 4, .ink), (5, 4, 4, .ink), (6, 3, 4, .ink), (4, 6, 3, .ink), (5, 5, 3, .ink), (6, 4, 3, .ink), (4, 7, 2, .ink), (5, 6, 2, .ink), (6, 5, 2, .ink), (7, 4, 2, .ink), (5, 7, 1, .ink), (6, 6, 1, .ink), (7, 5, 1, .ink), (5, 8, 0, .ink), (6, 7, 0, .ink), (7, 6, 0, .ink), (8, 5, 0, .ink), (3, 5, 6, .mid), (4, 4, 6, .mid), (5, 3, 6, .mid), (3, 6, 5, .mid), (4, 5, 5, .mid), (5, 4, 5, .mid), (6, 3, 5, .mid), (4, 6, 4, .ink), (5, 5, 4, .ink), (6, 4, 4, .ink), (4, 7, 3, .ink), (5, 6, 3, .ink), (6, 5, 3, .ink), (7, 4, 3, .ink), (5, 7, 2, .ink), (6, 6, 2, .ink), (7, 5, 2, .ink), (5, 8, 1, .ink), (6, 7, 1, .ink), (7, 6, 1, .ink), (8, 5, 1, .ink), (6, 8, 0, .ink), (7, 7, 0, .ink), (8, 6, 0, .ink), (3, 6, 6, .mid), (4, 5, 6, .mid), (5, 4, 6, .mid), (6, 3, 6, .mid), (4, 6, 5, .mid), (5, 5, 5, .mid), (6, 4, 5, .mid), (4, 7, 4, .ink), (5, 6, 4, .ink), (6, 5, 4, .ink), (7, 4, 4, .ink), (5, 7, 3, .ink), (6, 6, 3, .ink), (7, 5, 3, .ink), (5, 8, 2, .ink), (6, 7, 2, .ink), (7, 6, 2, .ink), (8, 5, 2, .ink), (6, 8, 1, .ink), (7, 7, 1, .ink), (8, 6, 1, .ink), (4, 5, 7, .mid), (5, 4, 7, .mid), (4, 6, 6, .mid), (5, 5, 6, .mid), (6, 4, 6, .mid), (4, 7, 5, .mid), (5, 6, 5, .mid), (6, 5, 5, .mid), (7, 4, 5, .mid), (5, 7, 4, .ink), (6, 6, 4, .ink), (7, 5, 4, .ink), (5, 8, 3, .ink), (6, 7, 3, .ink), (7, 6, 3, .ink), (8, 5, 3, .red), (6, 8, 2, .ink), (7, 7, 2, .ink), (8, 6, 2, .ink), (4, 6, 7, .mid), (5, 5, 7, .mid), (6, 4, 7, .mid), (4, 7, 6, .mid), (5, 6, 6, .mid), (6, 5, 6, .mid), (7, 4, 6, .mid), (5, 7, 5, .mid), (6, 6, 5, .mid), (7, 5, 5, .mid), (5, 8, 4, .ink), (6, 7, 4, .ink), (7, 6, 4, .ink), (8, 5, 4, .red), (6, 8, 3, .ink), (7, 7, 3, .ink), (8, 6, 3, .red), (5, 5, 8, .mid), (5, 6, 7, .mid), (6, 5, 7, .mid), (5, 7, 6, .mid), (6, 6, 6, .mid), (7, 5, 6, .mid), (5, 8, 5, .mid), (6, 7, 5, .mid), (7, 6, 5, .mid), (8, 5, 5, .mid), (6, 8, 4, .ink), (7, 7, 4, .ink), (8, 6, 4, .red), (5, 6, 8, .mid), (6, 5, 8, .mid), (5, 7, 7, .mid), (6, 6, 7, .mid), (7, 5, 7, .mid), (5, 8, 6, .mid), (6, 7, 6, .mid), (7, 6, 6, .mid), (8, 5, 6, .mid), (6, 8, 5, .mid), (7, 7, 5, .mid), (8, 6, 5, .mid), (6, 6, 8, .mid), (6, 7, 7, .mid), (7, 6, 7, .mid), (6, 8, 6, .mid), (7, 7, 6, .mid), (8, 6, 6, .mid) ], gesture: .flash(cells: [(8, 5, 3), (8, 5, 4), (8, 6, 3), (8, 6, 4)], color: .red, hold: 0.16)) /// calendar control · 192 voxels public static let calendar = AIMVoxelModel(name: "calendar", label: "calendar control", note: "light plate, ink header, six-by-four day grid, red today", voxels: [ (0, 4, 0, .light), (0, 4, 1, .light), (1, 4, 0, .light), (0, 4, 2, .light), (1, 4, 1, .light), (2, 4, 0, .light), (0, 4, 3, .light), (1, 4, 2, .light), (0, 5, 2, .mid), (2, 4, 1, .light), (3, 4, 0, .light), (0, 4, 4, .light), (1, 4, 3, .light), (2, 4, 2, .light), (3, 4, 1, .light), (4, 4, 0, .light), (0, 4, 5, .light), (1, 4, 4, .light), (0, 5, 4, .mid), (2, 4, 3, .light), (3, 4, 2, .light), (2, 5, 2, .mid), (4, 4, 1, .light), (5, 4, 0, .light), (0, 4, 6, .light), (1, 4, 5, .light), (2, 4, 4, .light), (3, 4, 3, .light), (4, 4, 2, .light), (5, 4, 1, .light), (6, 4, 0, .light), (0, 4, 7, .light), (1, 4, 6, .light), (0, 5, 6, .mid), (2, 4, 5, .light), (3, 4, 4, .light), (2, 5, 4, .mid), (4, 4, 3, .light), (5, 4, 2, .light), (4, 5, 2, .mid), (6, 4, 1, .light), (7, 4, 0, .light), (0, 4, 8, .light), (1, 4, 7, .light), (2, 4, 6, .light), (3, 4, 5, .light), (4, 4, 4, .light), (5, 4, 3, .light), (6, 4, 2, .light), (7, 4, 1, .light), (8, 4, 0, .light), (0, 4, 9, .light), (1, 4, 8, .light), (0, 5, 8, .mid), (2, 4, 7, .light), (3, 4, 6, .light), (2, 5, 6, .mid), (4, 4, 5, .light), (5, 4, 4, .light), (4, 5, 4, .mid), (6, 4, 3, .light), (7, 4, 2, .light), (6, 5, 2, .mid), (8, 4, 1, .light), (9, 4, 0, .light), (0, 4, 10, .light), (1, 4, 9, .light), (2, 4, 8, .light), (3, 4, 7, .light), (4, 4, 6, .light), (5, 4, 5, .light), (6, 4, 4, .light), (7, 4, 3, .light), (8, 4, 2, .light), (9, 4, 1, .light), (10, 4, 0, .light), (0, 4, 11, .light), (1, 4, 10, .light), (0, 5, 10, .ink), (2, 4, 9, .light), (3, 4, 8, .light), (2, 5, 8, .mid), (4, 4, 7, .light), (5, 4, 6, .light), (4, 5, 6, .mid), (6, 4, 5, .light), (7, 4, 4, .light), (6, 5, 4, .mid), (8, 4, 3, .light), (9, 4, 2, .light), (8, 5, 2, .mid), (10, 4, 1, .light), (11, 4, 0, .light), (1, 4, 11, .light), (0, 5, 11, .ink), (2, 4, 10, .light), (1, 5, 10, .ink), (3, 4, 9, .light), (4, 4, 8, .light), (5, 4, 7, .light), (6, 4, 6, .light), (7, 4, 5, .light), (8, 4, 4, .light), (9, 4, 3, .light), (10, 4, 2, .light), (11, 4, 1, .light), (2, 4, 11, .light), (1, 5, 11, .ink), (3, 4, 10, .light), (2, 5, 10, .ink), (4, 4, 9, .light), (5, 4, 8, .light), (4, 5, 8, .mid), (6, 4, 7, .light), (7, 4, 6, .light), (6, 5, 6, .red), (8, 4, 5, .light), (9, 4, 4, .light), (8, 5, 4, .mid), (10, 4, 3, .light), (11, 4, 2, .light), (10, 5, 2, .mid), (3, 4, 11, .light), (2, 5, 11, .ink), (4, 4, 10, .light), (3, 5, 10, .ink), (5, 4, 9, .light), (6, 4, 8, .light), (7, 4, 7, .light), (8, 4, 6, .light), (9, 4, 5, .light), (10, 4, 4, .light), (11, 4, 3, .light), (4, 4, 11, .light), (3, 5, 11, .ink), (5, 4, 10, .light), (4, 5, 10, .ink), (6, 4, 9, .light), (7, 4, 8, .light), (6, 5, 8, .mid), (8, 4, 7, .light), (9, 4, 6, .light), (8, 5, 6, .mid), (10, 4, 5, .light), (11, 4, 4, .light), (10, 5, 4, .mid), (5, 4, 11, .light), (4, 5, 11, .ink), (6, 4, 10, .light), (5, 5, 10, .ink), (7, 4, 9, .light), (8, 4, 8, .light), (9, 4, 7, .light), (10, 4, 6, .light), (11, 4, 5, .light), (6, 4, 11, .light), (5, 5, 11, .ink), (7, 4, 10, .light), (6, 5, 10, .ink), (8, 4, 9, .light), (9, 4, 8, .light), (8, 5, 8, .mid), (10, 4, 7, .light), (11, 4, 6, .light), (10, 5, 6, .mid), (7, 4, 11, .light), (6, 5, 11, .ink), (8, 4, 10, .light), (7, 5, 10, .ink), (9, 4, 9, .light), (10, 4, 8, .light), (11, 4, 7, .light), (8, 4, 11, .light), (7, 5, 11, .ink), (9, 4, 10, .light), (8, 5, 10, .ink), (10, 4, 9, .light), (11, 4, 8, .light), (10, 5, 8, .mid), (9, 4, 11, .light), (8, 5, 11, .ink), (10, 4, 10, .light), (9, 5, 10, .ink), (11, 4, 9, .light), (10, 4, 11, .light), (9, 5, 11, .ink), (11, 4, 10, .light), (10, 5, 10, .ink), (11, 4, 11, .light), (10, 5, 11, .ink), (11, 5, 10, .ink), (11, 5, 11, .ink) ], gesture: .cycle(cells: [(6, 5, 6), (8, 5, 6), (4, 5, 6), (10, 5, 6)], color: .red)) /// крест · 72 voxels public static let krest = AIMVoxelModel(name: "krest", label: "крест", note: "четыре луча от центра, красный воксель это точка баланса, она ходит по вертикали", voxels: [ (1, 5, 5, .ink), (5, 5, 1, .ink), (1, 5, 6, .ink), (1, 6, 5, .ink), (2, 5, 5, .mid), (5, 5, 2, .mid), (5, 6, 1, .ink), (6, 5, 1, .ink), (1, 6, 6, .ink), (2, 5, 6, .mid), (2, 6, 5, .mid), (3, 5, 5, .mid), (5, 5, 3, .mid), (5, 6, 2, .mid), (6, 5, 2, .mid), (6, 6, 1, .ink), (2, 6, 6, .mid), (3, 5, 6, .mid), (3, 6, 5, .mid), (4, 5, 5, .light), (5, 5, 4, .light), (5, 6, 3, .mid), (6, 5, 3, .mid), (6, 6, 2, .mid), (3, 6, 6, .mid), (4, 5, 6, .light), (4, 6, 5, .light), (5, 5, 5, .light), (5, 6, 4, .light), (6, 5, 4, .light), (6, 6, 3, .mid), (4, 6, 6, .light), (5, 5, 6, .light), (5, 6, 5, .light), (6, 5, 5, .light), (6, 6, 4, .light), (5, 5, 7, .light), (5, 6, 6, .light), (6, 5, 6, .red), (6, 6, 5, .light), (7, 5, 5, .light), (5, 5, 8, .mid), (5, 6, 7, .light), (6, 5, 7, .light), (6, 6, 6, .light), (7, 5, 6, .light), (7, 6, 5, .light), (8, 5, 5, .mid), (5, 5, 9, .mid), (5, 6, 8, .mid), (6, 5, 8, .mid), (6, 6, 7, .light), (7, 6, 6, .light), (8, 5, 6, .mid), (8, 6, 5, .mid), (9, 5, 5, .mid), (5, 5, 10, .ink), (5, 6, 9, .mid), (6, 5, 9, .mid), (6, 6, 8, .mid), (8, 6, 6, .mid), (9, 5, 6, .mid), (9, 6, 5, .mid), (10, 5, 5, .ink), (5, 6, 10, .ink), (6, 5, 10, .ink), (6, 6, 9, .mid), (9, 6, 6, .mid), (10, 5, 6, .ink), (10, 6, 5, .ink), (6, 6, 10, .ink), (10, 6, 6, .ink) ], gesture: .cycle(cells: [(6, 5, 8), (6, 5, 6), (6, 5, 4), (6, 5, 6)], color: .red)) /// style os · voxel hanger · 46 voxels public static let style = AIMVoxelModel(name: "style", label: "style os · voxel hanger", note: "hanger in cubes: ink bar, mid shoulders, ink neck, red hook tip – the one dirty accent", voxels: [ (1, 5, 2, .ink), (1, 6, 2, .ink), (2, 5, 2, .ink), (2, 5, 3, .mid), (2, 6, 2, .ink), (3, 5, 2, .ink), (2, 6, 3, .mid), (3, 6, 2, .ink), (4, 5, 2, .ink), (3, 5, 4, .mid), (4, 6, 2, .ink), (5, 5, 2, .ink), (3, 6, 4, .mid), (5, 6, 2, .ink), (6, 5, 2, .ink), (4, 5, 5, .mid), (6, 6, 2, .ink), (7, 5, 2, .ink), (4, 6, 5, .mid), (7, 6, 2, .ink), (8, 5, 2, .ink), (5, 5, 6, .mid), (8, 6, 2, .ink), (9, 5, 2, .ink), (5, 5, 7, .ink), (5, 6, 6, .mid), (6, 5, 6, .mid), (7, 5, 5, .mid), (8, 5, 4, .mid), (9, 5, 3, .mid), (9, 6, 2, .ink), (10, 5, 2, .ink), (5, 6, 7, .ink), (6, 5, 7, .ink), (6, 6, 6, .mid), (7, 6, 5, .mid), (8, 6, 4, .mid), (9, 6, 3, .mid), (10, 6, 2, .ink), (6, 5, 8, .ink), (6, 6, 7, .ink), (6, 5, 9, .ink), (6, 5, 10, .ink), (7, 5, 11, .red), (8, 5, 11, .red), (9, 5, 10, .red) ], gesture: .flash(cells: [(7, 5, 11), (8, 5, 11), (9, 5, 10)], color: .light, hold: 0.16)) /// Catalog order: family, relay, aside, prism, calendar, krest, style. public static let all: [AIMVoxelModel] = [family, relay, aside, prism, calendar, krest, style] public static func model(named name: String) -> AIMVoxelModel? { all.first { $0.name == name } } }