{"id":13822945,"url":"https://github.com/heestand-xyz/PixelKit","last_synced_at":"2025-05-16T17:32:52.149Z","repository":{"id":38283479,"uuid":"142007910","full_name":"heestand-xyz/PixelKit","owner":"heestand-xyz","description":"Live Graphics in Swift \u0026 Metal","archived":true,"fork":false,"pushed_at":"2023-02-05T03:06:46.000Z","size":64762,"stargazers_count":892,"open_issues_count":3,"forks_count":66,"subscribers_count":26,"default_branch":"main","last_synced_at":"2025-05-13T20:10:59.572Z","etag":null,"topics":["graphics","ios","live","macos","metal","swift"],"latest_commit_sha":null,"homepage":"","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/heestand-xyz.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-07-23T11:57:37.000Z","updated_at":"2025-04-12T16:13:42.000Z","dependencies_parsed_at":"2023-02-18T21:31:14.587Z","dependency_job_id":null,"html_url":"https://github.com/heestand-xyz/PixelKit","commit_stats":null,"previous_names":["hexagons/pixelkit"],"tags_count":103,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/heestand-xyz%2FPixelKit","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/heestand-xyz%2FPixelKit/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/heestand-xyz%2FPixelKit/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/heestand-xyz%2FPixelKit/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/heestand-xyz","download_url":"https://codeload.github.com/heestand-xyz/PixelKit/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254576748,"owners_count":22094447,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["graphics","ios","live","macos","metal","swift"],"created_at":"2024-08-04T08:02:26.052Z","updated_at":"2025-05-16T17:32:47.139Z","avatar_url":"https://github.com/heestand-xyz.png","language":"Swift","funding_links":[],"categories":["Swift","Tools"],"sub_categories":["Frameworks • Libraries • Ecosystems"],"readme":"\u003cimg src=\"https://github.com/heestand-xyz/PixelKit/blob/main/Assets/Logo/pixels_logo_1k_bg.png?raw=true\" width=\"128\"/\u003e\n\n*Check out [AsyncGraphics](https://github.com/heestand-xyz/AsyncGraphics).\u003cbr\u003eInspired by PixelKit \u0026 RenderKit.*\n\n# PixelKit\n\nLive Graphics for iOS, macOS and tvOS\u003cbr\u003e\nRuns on [RenderKit](https://github.com/heestand-xyz/RenderKit), powered by Metal\n\nPixelKit combines custom shaders, metal performance shaders, core image filters and vision to create tools for real-time rendering.\n\nExamples:\n[Camera Effects](#example-camera-effects) -\n[Green Screen](#example-green-screen)\n\u003cbr\u003e\nInfo:\n[Coordinate Space](#coordinate-space) -\n[Blend Operators](#blend-operators) -\n[Effect Convenience Funcs](#effect-convenience-funcs) -\n[High Bit Mode](#high-bit-mode)\n\n| \u003cimg src=\"https://github.com/heestand-xyz/PixelKit/blob/main/Assets/Icons/thumb_camera.png?raw=true\" width=\"32\"/\u003e | \u003cimg src=\"https://github.com/heestand-xyz/PixelKit/blob/main/Assets/Icons/thumb_camera.png?raw=true\" width=\"32\"/\u003e | \u003cimg src=\"https://github.com/heestand-xyz/PixelKit/blob/main/Assets/Icons/thumb_image.png?raw=true\" width=\"32\"/\u003e | \u003cimg src=\"https://github.com/heestand-xyz/PixelKit/blob/main/Assets/Icons/thumb_video.png?raw=true\" width=\"32\"/\u003e | \u003cimg src=\"https://github.com/heestand-xyz/PixelKit/blob/main/Assets/Icons/thumb_screenCapture.png?raw=true\" width=\"32\"/\u003e | \u003cimg src=\"https://github.com/heestand-xyz/PixelKit/blob/main/Assets/Icons/thumb_stream.png?raw=true\" width=\"32\"/\u003e | \u003cimg src=\"https://github.com/heestand-xyz/PixelKit/blob/main/Assets/Icons/thumb_slope.png?raw=true\" width=\"32\"/\u003e |\n| --- | --- | --- | --- | --- | --- | --- |\n| CameraPIX | DepthCameraPIX | ImagePIX | VideoPIX | ScreenCapturePIX | StreamInPIX | SlopePIX |\n\n| \u003cimg src=\"https://github.com/heestand-xyz/PixelKit/blob/main/Assets/Icons/%20thumb_color.png?raw=true\" width=\"32\"/\u003e | \u003cimg src=\"https://github.com/heestand-xyz/PixelKit/blob/main/Assets/Icons/%20thumb_circle.png?raw=true\" width=\"32\"/\u003e | \u003cimg src=\"https://github.com/heestand-xyz/PixelKit/blob/main/Assets/Icons/thumb_rectangle.png?raw=true\" width=\"32\"/\u003e | \u003cimg src=\"https://github.com/heestand-xyz/PixelKit/blob/main/Assets/Icons/%20thumb_polygon.png?raw=true\" width=\"32\"/\u003e | \u003cimg src=\"https://github.com/heestand-xyz/PixelKit/blob/main/Assets/Icons/%20thumb_arc.png?raw=true\" width=\"32\"/\u003e | \u003cimg src=\"https://github.com/heestand-xyz/PixelKit/blob/main/Assets/Icons/%20thumb_line.png?raw=true\" width=\"32\"/\u003e | \u003cimg src=\"https://github.com/heestand-xyz/PixelKit/blob/main/Assets/Icons/%20thumb_gradient.png?raw=true\" width=\"32\"/\u003e | \u003cimg src=\"https://github.com/heestand-xyz/PixelKit/blob/main/Assets/Icons/thumb_stack.png?raw=true\" width=\"32\"/\u003e |\n| --- | --- | --- | --- | --- | --- | --- | --- |\n| ColorPIX | CirclePIX | RectanglePIX | PolygonPIX | ArcPIX | LinePIX | GradientPIX | StackPIX |\n\n| \u003cimg src=\"https://github.com/heestand-xyz/PixelKit/blob/main/Assets/Icons/%20thumb_noise.png?raw=true\" width=\"32\"/\u003e | \u003cimg src=\"https://github.com/heestand-xyz/PixelKit/blob/main/Assets/Icons/thumb_text.png?raw=true\" width=\"32\"/\u003e | \u003cimg src=\"https://github.com/heestand-xyz/PixelKit/blob/main/Assets/Icons/thumb_metal.png?raw=true\" width=\"32\"/\u003e | \u003cimg src=\"https://github.com/heestand-xyz/PixelKit/blob/main/Assets/Icons/thumb_twirl.png?raw=true\" width=\"32\"/\u003e | \u003cimg src=\"https://github.com/heestand-xyz/PixelKit/blob/main/Assets/Icons/thumb_feedback.png?raw=true\" width=\"32\"/\u003e | \u003cimg src=\"https://github.com/heestand-xyz/PixelKit/blob/main/Assets/Icons/thumb_delay.png?raw=true\" width=\"32\"/\u003e | \u003cimg src=\"https://github.com/heestand-xyz/PixelKit/blob/main/Assets/Icons/thumb_sharpen.png?raw=true\" width=\"32\"/\u003e | \u003cimg src=\"https://github.com/heestand-xyz/PixelKit/blob/main/Assets/Icons/thumb_stream.png?raw=true\" width=\"32\"/\u003e |\n| --- | --- | --- | --- | --- | --- | --- | --- |\n| NoisePIX | TextPIX | MetalPIX | TwirlPIX | FeedbackPIX | DelayPIX | SharpenPIX | StreamOutPIX |\n\n| \u003cimg src=\"https://github.com/heestand-xyz/PixelKit/blob/main/Assets/Icons/thumb_levels.png?raw=true\" width=\"32\"/\u003e | \u003cimg src=\"https://github.com/heestand-xyz/PixelKit/blob/main/Assets/Icons/thumb_blur.png?raw=true\" width=\"32\"/\u003e | \u003cimg src=\"https://github.com/heestand-xyz/PixelKit/blob/main/Assets/Icons/thumb_edge.png?raw=true\" width=\"32\"/\u003e | \u003cimg src=\"https://github.com/heestand-xyz/PixelKit/blob/main/Assets/Icons/thumb_threshold.png?raw=true\" width=\"32\"/\u003e | \u003cimg src=\"https://github.com/heestand-xyz/PixelKit/blob/main/Assets/Icons/thumb_quantize.png?raw=true\" width=\"32\"/\u003e | \u003cimg src=\"https://github.com/heestand-xyz/PixelKit/blob/main/Assets/Icons/thumb_transform.png?raw=true\" width=\"32\"/\u003e | \u003cimg src=\"https://github.com/heestand-xyz/PixelKit/blob/main/Assets/Icons/thumb_kaleidoscope.png?raw=true\" width=\"32\"/\u003e |\n| --- | --- | --- | --- | --- | --- | --- |\n| LevelsPIX | BlurPIX | EdgePIX | ThresholdPIX | QuantizePIX | TransformPIX | KaleidoscopePIX |\n\n| \u003cimg src=\"https://github.com/heestand-xyz/PixelKit/blob/main/Assets/Icons/thumb_channelMix.png?raw=true\" width=\"32\"/\u003e | \u003cimg src=\"https://github.com/heestand-xyz/PixelKit/blob/main/Assets/Icons/thumb_chromaKey.png?raw=true\" width=\"32\"/\u003e | \u003cimg src=\"https://github.com/heestand-xyz/PixelKit/blob/main/Assets/Icons/thumb_cornerPin.png?raw=true\" width=\"32\"/\u003e | \u003cimg src=\"https://github.com/heestand-xyz/PixelKit/blob/main/Assets/Icons/thumb_hueSat.png?raw=true\" width=\"32\"/\u003e | \u003cimg src=\"https://github.com/heestand-xyz/PixelKit/blob/main/Assets/Icons/thumb_flipFlop.png?raw=true\" width=\"32\"/\u003e | \u003cimg src=\"https://github.com/heestand-xyz/PixelKit/blob/main/Assets/Icons/thumb_range.png?raw=true\" width=\"32\"/\u003e | \u003cimg src=\"https://github.com/heestand-xyz/PixelKit/blob/main/Assets/Icons/thumb_star.png?raw=true\" width=\"32\"/\u003e |\n| --- | --- | --- | --- | --- | --- | --- |\n| ChannelMixPIX | ChromaKeyPIX | CornerPinPIX | ColorShiftPIX | FlipFlopPIX | RangePIX | StarPIX |\n\n| \u003cimg src=\"https://github.com/heestand-xyz/PixelKit/blob/main/Assets/Icons/thumb_sepia.png?raw=true\" width=\"32\"/\u003e | \u003cimg src=\"https://github.com/heestand-xyz/PixelKit/blob/main/Assets/Icons/thumb_convert.png?raw=true\" width=\"32\"/\u003e | \u003cimg src=\"https://github.com/heestand-xyz/PixelKit/blob/main/Assets/Icons/thumb_reduce.png?raw=true\" width=\"32\"/\u003e | \u003cimg src=\"https://github.com/heestand-xyz/PixelKit/blob/main/Assets/Icons/thumb_clamp.png?raw=true\" width=\"32\"/\u003e | \u003cimg src=\"https://github.com/heestand-xyz/PixelKit/blob/main/Assets/Icons/thumb_freeze.png?raw=true\" width=\"32\"/\u003e | \u003cimg src=\"https://github.com/heestand-xyz/PixelKit/blob/main/Assets/Icons/thumb_flare.png?raw=true\" width=\"32\"/\u003e | \u003cimg src=\"https://github.com/heestand-xyz/PixelKit/blob/main/Assets/Icons/thumb_airplay.png?raw=true\" width=\"32\"/\u003e | \u003cimg src=\"https://github.com/heestand-xyz/PixelKit/blob/main/Assets/Icons/thumb_rec.png?raw=true\" width=\"32\"/\u003e |\n| --- | --- | --- | --- | --- | --- | --- | --- |\n| SepiaPIX | ConvertPIX | ReducePIX | ClampPIX | FreezePIX | FlarePIX | AirPlayPIX | RecordPIX |\n\n| \u003cimg src=\"https://github.com/heestand-xyz/PixelKit/blob/main/Assets/Icons/thumb_blend.png?raw=true\" width=\"32\"/\u003e | \u003cimg src=\"https://github.com/heestand-xyz/PixelKit/blob/main/Assets/Icons/thumb_cross.png?raw=true\" width=\"32\"/\u003e | \u003cimg src=\"https://github.com/heestand-xyz/PixelKit/blob/main/Assets/Icons/thumb_lookup.png?raw=true\" width=\"32\"/\u003e | \u003cimg src=\"https://github.com/heestand-xyz/PixelKit/blob/main/Assets/Icons/thumb_displace.png?raw=true\" width=\"32\"/\u003e | \u003cimg src=\"https://github.com/heestand-xyz/PixelKit/blob/main/Assets/Icons/thumb_remap.png?raw=true\" width=\"32\"/\u003e | \u003cimg src=\"https://github.com/heestand-xyz/PixelKit/blob/main/Assets/Icons/thumb_reorder.png?raw=true\" width=\"32\"/\u003e | \u003cimg src=\"https://github.com/heestand-xyz/PixelKit/blob/main/Assets/Icons/thumb_res.png?raw=true\" width=\"32\"/\u003e | \u003cimg src=\"https://github.com/heestand-xyz/PixelKit/blob/main/Assets/Icons/thumb_crop.png?raw=true\" width=\"32\"/\u003e |\n| --- | --- | --- | --- | --- | --- | --- | --- |\n| BlendPIX | CrossPIX | LookupPIX | DisplacePIX | RemapPIX | ReorderPIX | ResolutionPIX | CropPIX |\n\n| \u003cimg src=\"https://github.com/heestand-xyz/PixelKit/blob/main/Assets/Icons/thumb_blend.png?raw=true\" width=\"32\"/\u003e | \u003cimg src=\"https://github.com/heestand-xyz/PixelKit/blob/main/Assets/Icons/thumb_levels.png?raw=true\" width=\"32\"/\u003e | \u003cimg src=\"https://github.com/heestand-xyz/PixelKit/blob/main/Assets/Icons/thumb_lumaBlur.png?raw=true\" width=\"32\"/\u003e | \u003cimg src=\"https://github.com/heestand-xyz/PixelKit/blob/main/Assets/Icons/thumb_transform.png?raw=true\" width=\"32\"/\u003e | \u003cimg src=\"https://github.com/heestand-xyz/PixelKit/blob/main/Assets/Icons/thumb_delay.png?raw=true\" width=\"32\"/\u003e | \u003cimg src=\"https://github.com/heestand-xyz/PixelKit/blob/main/Assets/Icons/thumb_array.png?raw=true\" width=\"32\"/\u003e |\n| --- | --- | --- | --- | --- | --- |\n| BlendsPIX | LumaLevelsPIX | LumaBlurPIX | LumaTransformPIX | TimeMachinePIX | ArrayPIX |\n\n--- \n\n## Install\n\n### Swift Package\n\n~~~~swift\n.package(url: \"https://github.com/heestand-xyz/PixelKit\", from: \"3.0.0\")\n~~~~\n\n## Setup\n\n### SwiftUI\n\n~~~~swift\nimport SwiftUI\nimport PixelKit\n\nstruct ContentView: View {\n    \n    @StateObject var circlePix = CirclePIX()\n    @StateObject var blurPix = BlurPIX()\n    \n    var body: some View {\n        PixelView(pix: blurPix)\n            .onAppear {\n                blurPix.input = circlePix\n                blurPix.radius = 0.25\n            }\n    }\n}\n~~~~\n\n### UIKit\n\n~~~~swift\nimport UIKit\nimport PixelKit\n\nclass ViewController: UIViewController {\n\n    override func viewDidLoad() {\n        super.viewDidLoad()\n\n        let circlePix = CirclePIX()\n\n        let blurPix = BlurPIX()\n        blurPix.input = circlePix\n        blurPix.radius = 0.25\n\n        let finalPix: PIX = blurPix\n        finalPix.view.frame = view.bounds\n        view.addSubview(finalPix.view)\n    }\n}\n~~~~\n\n\n## Resolution\n\nIn PixelKit all PIXs have a resolution. Some PIXs have defined resolutions (default to `.auto`) and some PIXs have derived resolutions.\n\nThe `.auto` resolution will fill up the view and get the correct resolution based on the view size. If a view is 100x100 points, the resolution will be 200x200 pixels on macOS and 300x300 pixels on iPhone.\n\nImport the resolution package to work with resolutions:\n\n```swift\nimport Resolution\n```\n\nYou can multiply and divide resolutions with a `CGFloat` or `Int`.\n\nThere are predefined resolutions like `._1080p` \u0026 `._4K`.\n  \n\n## Rendered Image\n\n~~~~swift\n.renderedImage // UIImage or NSImage\n.renderedTexture // MTLTexture\n~~~~\n\n\n### Example: Camera Effects\n\n| \u003cimg src=\"https://github.com/heestand-xyz/PixelKit/raw/main/Assets/Renders/pix_demo_01.jpg\" width=\"150\" height=\"100\"/\u003e | \u003cimg src=\"https://github.com/heestand-xyz/PixelKit/raw/main/Assets/Renders/pix_demo_02.jpg\" width=\"140\" height=\"100\"/\u003e | \u003cimg src=\"https://github.com/heestand-xyz/PixelKit/raw/main/Assets/Renders/pix_demo_03.jpg\" width=\"140\" height=\"100\"/\u003e | \u003cimg src=\"https://github.com/heestand-xyz/PixelKit/raw/main/Assets/Renders/pix_demo_04.jpg\" width=\"150\" height=\"100\"/\u003e | \u003cimg src=\"https://github.com/heestand-xyz/PixelKit/raw/main/Assets/Renders/pix_demo_05.jpg\" width=\"150\" height=\"100\"/\u003e |\n| --- | --- | --- | --- | --- |\n\n```swift\nimport SwiftUI\nimport PixelKit\n\nclass ViewModel: ObservableObject {\n    \n    let camera: CameraPIX\n    let levels: LevelsPIX\n    let colorShift: ColorShiftPIX\n    let blur: BlurPIX\n    let circle: CirclePIX\n    \n    let finalPix: PIX\n    \n    init() {\n        \n        camera = CameraPIX()\n        camera.cameraResolution = ._1080p\n\n        levels = LevelsPIX()\n        levels.input = camera\n        levels.brightness = 1.5\n        levels.gamma = 0.5\n\n        colorShift = ColorShiftPIX()\n        colorShift.input = levels\n        colorShift.saturation = 0.5\n\n        blur = BlurPIX()\n        blur.input = colorShift\n        blur.radius = 0.25\n\n        circle = CirclePIX(at: .square(1080))\n        circle.radius = 0.45\n        circle.backgroundColor = .clear\n\n        finalPix = blur \u0026 (camera * circle)\n    }\n}\n\nstruct ContentView: View {\n    \n    @StateObject var viewModel = ViewModel()\n    \n    var body: some View {\n        PixelView(pix: viewModel.finalPix)\n    }\n}\n```\n\nThis can also be done with [Effect Convenience Funcs](#effect-convenience-funcs):\u003cbr\u003e\n```swift\nlet pix = CameraPIX().pixBrightness(1.5).pixGamma(0.5).pixSaturation(0.5).pixBlur(0.25)\n```\n\nRemeber to add `NSCameraUsageDescription` to your *Info.plist*\n\n\n### Example: Green Screen\n\n| \u003cimg src=\"https://github.com/heestand-xyz/PixelKit/raw/main/Assets/Renders/Pixels-GreenScreen-1.png\" width=\"150\" height=\"100\"/\u003e | \u003cimg src=\"https://github.com/heestand-xyz/PixelKit/raw/main/Assets/Renders/Pixels-GreenScreen-2.png\" width=\"140\" height=\"100\"/\u003e | \u003cimg src=\"https://github.com/heestand-xyz/PixelKit/raw/main/Assets/Renders/Pixels-GreenScreen-3.png\" width=\"140\" height=\"100\"/\u003e | \u003cimg src=\"https://github.com/heestand-xyz/PixelKit/raw/main/Assets/Renders/Pixels-GreenScreen-4.png\" width=\"150\" height=\"100\"/\u003e |\n| --- | --- | --- | --- |\n\n`import RenderKit\nimport PixelKit`\n\n~~~~swift\nlet cityImage = ImagePIX()\ncityImage.image = UIImage(named: \"city\")\n\nlet supermanVideo = VideoPIX()\nsupermanVideo.load(fileNamed: \"superman\", withExtension: \"mov\")\n\nlet supermanKeyed = ChromaKeyPIX()\nsupermanKeyed.input = supermanVideo\nsupermanKeyed.keyColor = .green\n\nlet blendPix = BlendPIX()\nblendPix.blendingMode = .over\nblendPix.inputA = cityImage\nblendPix.inputB = supermanKeyed\n\nlet finalPix: PIX = blendPix\nfinalPix.view.frame = view.bounds\nview.addSubview(finalPix.view)\n~~~~ \n\nThis can also be done with [Blend Operators](#blend-operators) and [Effect Convenience Funcs](#effect-convenience-funcs):\u003cbr\u003e\n```swift\nlet pix = cityImage \u0026 supermanVideo.pixChromaKey(.green)\n```\n\n\n### Example: Depth Camera\n\n`\nimport RenderKit\nimport PixelKit`\n\n~~~~swift\nlet cameraPix = CameraPIX()\ncameraPix.camera = .front\n\nlet depthCameraPix = DepthCameraPIX.setup(with: cameraPix)\n\nlet levelsPix = LevelsPIX()\nlevelsPix.input = depthCameraPix\nlevelsPix.inverted = true\n\nlet lumaBlurPix = cameraPix.pixLumaBlur(pix: levelsPix, radius: 0.1)\n\nlet finalPix: PIX = lumaBlurPix\nfinalPix.view.frame = view.bounds\nview.addSubview(finalPix.view)\n~~~~ \n\nThe `DepthCameraPIX` was added in PixelKit `v0.8.4` and requires an iPhone X or newer.\n\nNote to use the `setup(with:filter:)` method of `DepthCameraPIX`.\u003cbr\u003e\nIt will take care of orientation, color and enable depth on the `CameraPIX`.\n\nTo gain access to depth values ouside of the 0.0 and 1.0 bounds,\u003cbr\u003e\nenable `16 bit` mode like this: `PixelKit.main.render.bits = ._16`\n\n\n### Example: Multi Camera\n\n~~~~swift\nlet cameraPix = CameraPIX()\ncameraPix.camera = .back\n\nlet multiCameraPix = MultiCameraPIX.setup(with: cameraPix, camera: .front)\n\nlet movedMultiCameraPix = multiCameraPix.pixScale(by: 0.25).pixTranslate(x: 0.375 * (9 / 16), y: 0.375)\n\nlet finalPix: PIX = camearPix \u0026 movedMultiCameraPix\nfinalPix.view.frame = view.bounds\nview.addSubview(finalPix.view)\n~~~~ \n\nNote `MultiCameraPIX` requires iOS 13. \n\n## Coordinate Space\n\nThe PixelKit coordinate space is normailzed to the vertical axis (1.0 in height) with the origin (0.0, 0.0) in the center.\u003cbr\u003e\nNote that compared to native UIKit and SwiftUI views the vertical axis is flipped and origin is moved, this is more convinent when working with graphics in PixelKit.\nA full rotation is defined by 1.0 \n\n\u003cb\u003eCenter:\u003c/b\u003e CGPoint(x: 0, y: 0)\u003cbr\u003e\n\u003cb\u003eBottom Left:\u003c/b\u003e CGPoint(x: -0.5 * aspectRatio, y: -0.5)\u003cbr\u003e\n\u003cb\u003eTop Right:\u003c/b\u003e CGPoint(x: 0.5 * aspectRatio, y: 0.5)\u003cbr\u003e\n\n\u003cb\u003eTip:\u003c/b\u003e `Resolution` has an `.aspect` property:\u003cbr\u003e\n`let aspectRatio: CGFloat = Resolution._1080p.aspect`\n\n## Blend Operators\n\nA quick and convenient way to blend PIXs\u003cbr\u003e\nThese are the supported `BlendingMode` operators:\n\n| `\u0026` | `!\u0026` | `+` | `-` | `*` | `**` | `!**` | `%` | `~` | `°` |\n| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |\n| .over | .under | .add | .subtract | .multiply | .power | .gamma | .difference | .average | cosine |\n\n\n| `\u003c\u003e` | `\u003e\u003c` | `++` | `--` | `\u003c-\u003e` | `\u003e-\u003c` | `+-+` |\n| --- | --- | --- | --- | --- | --- | --- |\n| .minimum | .maximum | .addWithAlpha | .subtractWithAlpha | inside | outside | exclusiveOr |\n\n```swift\nlet blendPix = (CameraPIX() !** NoisePIX(at: .fullHD(.portrait))) * CirclePIX(at: .fullHD(.portrait))\n```\n\nThe default global blend operator fill mode is `.fit`, change it like this:\u003cbr\u003e\n`PIX.blendOperators.globalPlacement = .fill`\n\n## Effect Convenience Funcs\n\n- \u003cb\u003e.pixScaleResolution(to: ._1080p * 0.5)\u003c/b\u003e -\u003e ResolutionPIX\n- \u003cb\u003e.pixScaleResolution(by: 0.5)\u003c/b\u003e -\u003e ResolutionPIX\n- \u003cb\u003e.pixBrightness(0.5)\u003c/b\u003e -\u003e LevelsPIX\n- \u003cb\u003e.pixDarkness(0.5)\u003c/b\u003e -\u003e LevelsPIX\n- \u003cb\u003e.pixContrast(0.5)\u003c/b\u003e -\u003e LevelsPIX\n- \u003cb\u003e.pixGamma(0.5)\u003c/b\u003e -\u003e LevelsPIX\n- \u003cb\u003e.pixInvert()\u003c/b\u003e -\u003e LevelsPIX\n- \u003cb\u003e.pixOpacity(0.5)\u003c/b\u003e -\u003e LevelsPIX\n- \u003cb\u003e.pixBlur(0.5)\u003c/b\u003e -\u003e BlurPIX\n- \u003cb\u003e.pixEdge()\u003c/b\u003e -\u003e EdgePIX\n- \u003cb\u003e.pixThreshold(at: 0.5)\u003c/b\u003e -\u003e ThresholdPIX\n- \u003cb\u003e.pixQuantize(by: 0.5)\u003c/b\u003e -\u003e QuantizePIX\n- \u003cb\u003e.pixPosition(at: CGPoint(x: 0.5, y: 0.5))\u003c/b\u003e -\u003e TransformPIX\n- \u003cb\u003e.pixRotatate(by: 0.5)\u003c/b\u003e -\u003e TransformPIX\n- \u003cb\u003e.pixRotatate(byRadians: .pi)\u003c/b\u003e -\u003e TransformPIX\n- \u003cb\u003e.pixRotatate(byDegrees: 180)\u003c/b\u003e -\u003e TransformPIX\n- \u003cb\u003e.pixScale(by: 0.5)\u003c/b\u003e -\u003e TransformPIX\n- \u003cb\u003e.pixKaleidoscope()\u003c/b\u003e -\u003e KaleidoscopePIX\n- \u003cb\u003e.pixTwirl(0.5)\u003c/b\u003e -\u003e TwirlPIX\n- \u003cb\u003e.pixSwap(.red, .blue)\u003c/b\u003e -\u003e ChannelMixPIX\n- \u003cb\u003e.pixChromaKey(.green)\u003c/b\u003e -\u003e ChromaKeyPIX\n- \u003cb\u003e.pixHue(0.5)\u003c/b\u003e -\u003e ColorShiftPIX\n- \u003cb\u003e.pixSaturation(0.5)\u003c/b\u003e -\u003e ColorShiftPIX\n- \u003cb\u003e.pixCrop(CGRect(x: 0.25, y 0.25, width: 0.5, height: 0.5))\u003c/b\u003e -\u003e CropPIX\n- \u003cb\u003e.pixFlipX()\u003c/b\u003e -\u003e FlipFlopPIX\n- \u003cb\u003e.pixFlipY()\u003c/b\u003e -\u003e FlipFlopPIX\n- \u003cb\u003e.pixFlopLeft()\u003c/b\u003e -\u003e FlipFlopPIX\n- \u003cb\u003e.pixFlopRight()\u003c/b\u003e -\u003e FlipFlopPIX\n- \u003cb\u003e.pixRange(inLow: 0.0, inHigh: 0.5, outLow: 0.5, outHigh: 1.0)\u003c/b\u003e -\u003e RangePIX\n- \u003cb\u003e.pixRange(inLow: .clear, inHigh: .gray, outLow: .gray, outHigh: .white)\u003c/b\u003e -\u003e RangePIX\n- \u003cb\u003e.pixSharpen()\u003c/b\u003e -\u003e SharpenPIX\n- \u003cb\u003e.pixSlope()\u003c/b\u003e - \u003e SlopePIX\n- \u003cb\u003e.pixVignetting(radius: 0.5, inset: 0.25, gamma: 0.5)\u003c/b\u003e -\u003e LumaLevelsPIX\n- \u003cb\u003e.pixLookup(pix: pixB, axis: .x)\u003c/b\u003e -\u003e LookupPIX\n- \u003cb\u003e.pixLumaBlur(pix: pixB, radius: 0.5)\u003c/b\u003e -\u003e LumaBlurPIX\n- \u003cb\u003e.pixLumaLevels(pix: pixB, brightness: 2.0)\u003c/b\u003e -\u003e LumaLevelsPIX\n- \u003cb\u003e.pixDisplace(pix: pixB, distance: 0.5)\u003c/b\u003e -\u003e DisplacePIX\n- \u003cb\u003e.pixRemap(pix: pixB)\u003c/b\u003e -\u003e RemapPIX\n\nKeep in mind that these funcs will create new PIXs.\u003cbr\u003e\nBe careful of overloading GPU memory, some funcs create several PIXs.\n\n## High Bit Mode\n\nSome effects like \u003cb\u003eDisplacePIX\u003c/b\u003e and \u003cb\u003eSlopePIX\u003c/b\u003e can benefit from a higher bit depth.\u003cbr\u003e\nThe default is 8 bits. Change it like this:\n`PixelKit.main.render.bits = ._16`\n\nEnable high bit mode before you create any PIXs.\n\nNote resources do not support higher bits yet.\u003cbr\u003e\nThere is currently there is some gamma offset with resources.\n\n## MetalPIXs\n\n\u003cimg src=\"https://github.com/heestand-xyz/PixelKit/raw/main/Assets/Renders/uv_1080p.png\" width=\"150\"/\u003e\n\n~~~~swift\nlet metalPix = MetalPIX(at: ._1080p, code:\n    \"\"\"\n    pix = float4(u, v, 0.0, 1.0);\n    \"\"\"\n)\n~~~~\n\n~~~~swift\nlet metalEffectPix = MetalEffectPIX(code:\n    \"\"\"\n    float gamma = 0.25;\n    pix = pow(input, 1.0 / gamma);\n    \"\"\"\n)\nmetalEffectPix.input = CameraPIX()\n~~~~\n\n~~~~swift\nlet metalMergerEffectPix = MetalMergerEffectPIX(code:\n    \"\"\"\n    pix = pow(inputA, 1.0 / inputB);\n    \"\"\"\n)\nmetalMergerEffectPix.inputA = CameraPIX()\nmetalMergerEffectPix.inputB = ImagePIX(\"img_name\")\n~~~~\n\n~~~~swift\nlet metalMultiEffectPix = MetalMultiEffectPIX(code:\n    \"\"\"\n    float4 inPixA = inTexs.sample(s, uv, 0);\n    float4 inPixB = inTexs.sample(s, uv, 1);\n    float4 inPixC = inTexs.sample(s, uv, 2);\n    pix = inPixA + inPixB + inPixC;\n    \"\"\"\n)\nmetalMultiEffectPix.inputs = [ImagePIX(\"img_a\"), ImagePIX(\"img_b\"), ImagePIX(\"img_c\")]\n~~~~\n\n### Uniforms:\n\n~~~~swift\nvar lumUniform = MetalUniform(name: \"lum\")\nlet metalPix = MetalPIX(at: ._1080p, code:\n    \"\"\"\n    pix = float4(in.lum, in.lum, in.lum, 1.0);\n    \"\"\",\n    uniforms: [lumUniform]\n)\nlumUniform.value = 0.5\n~~~~\n\n### Notes:\n\n- To gain camera access, on macOS, check Camera in the App Sandbox in your Xcode project settings under Capabilities.\n\n---\n\ninspired by [TouchDesigner](https://derivative.ca)\ncreated by Anton [Heestand XYZ](http://heestand.xyz/)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fheestand-xyz%2FPixelKit","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fheestand-xyz%2FPixelKit","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fheestand-xyz%2FPixelKit/lists"}