{"id":15030442,"url":"https://github.com/onmyway133/roughswift","last_synced_at":"2025-05-16T15:09:49.338Z","repository":{"id":56921766,"uuid":"177608619","full_name":"onmyway133/RoughSwift","owner":"onmyway133","description":"🎃 Create hand-drawn, sketchy, comic shape in Swift","archived":false,"fork":false,"pushed_at":"2023-11-29T09:34:03.000Z","size":2004,"stargazers_count":1134,"open_issues_count":4,"forks_count":55,"subscribers_count":15,"default_branch":"master","last_synced_at":"2025-05-15T07:41:48.286Z","etag":null,"topics":["ios","swift","swiftui"],"latest_commit_sha":null,"homepage":"https://onmyway133.com","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/onmyway133.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-03-25T15:00:21.000Z","updated_at":"2025-05-03T20:32:27.000Z","dependencies_parsed_at":"2023-11-29T10:47:19.012Z","dependency_job_id":null,"html_url":"https://github.com/onmyway133/RoughSwift","commit_stats":{"total_commits":122,"total_committers":1,"mean_commits":122.0,"dds":0.0,"last_synced_commit":"738b334d83320152e8114d498c6a2ac0fcd195ef"},"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/onmyway133%2FRoughSwift","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/onmyway133%2FRoughSwift/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/onmyway133%2FRoughSwift/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/onmyway133%2FRoughSwift/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/onmyway133","download_url":"https://codeload.github.com/onmyway133/RoughSwift/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254554016,"owners_count":22090418,"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":["ios","swift","swiftui"],"created_at":"2024-09-24T20:13:21.707Z","updated_at":"2025-05-16T15:09:44.331Z","avatar_url":"https://github.com/onmyway133.png","language":"Swift","funding_links":[],"categories":[],"sub_categories":[],"readme":"![](Screenshots/s.png)\n\nCheckout https://indiegoodies.com/\n\n![](Screenshots/s1.png)\n\n## Description\n\nRoughSwift allows us to easily make shapes in hand drawn, sketchy, comic style in SwiftUI.\n\n- [x] Support iOS, tvOS\n- [x] Support all shapes: line, rectangle, circle, ellipse, linear path, arc, curve, polygon, svg path\n- [x] Generate `UIBezierPath` for `CAShapeLayer`\n- [x] Easy cusomizations with Options\n- [x] Easy composable APIs\n- [x] Convenient draw functions\n- [x] Platform independant APIs which can easily support new platforms\n- [x] Test coverage\n- [x] Immutable and type safe data structure\n- [ ] SVG elliptical arc\n\nThere are [Example](https://github.com/onmyway133/RoughSwift/tree/master/Example) project where you can explore further.\n\n## Basic\n\nUse `generator` in `draw` function to specify which shape to render. The returned `CALayer` contains the rendered result in correct `size` and is updated everytime `generator` is instructed.\n\nHere's how to draw a green rectangle\n\n![](Screenshots/green_rectangle.png)\n\n```swift\nRoughView()\n    .fill(.yellow)\n    .fillStyle(.hachure)\n    .hachureAngle(-41)\n    .hachureGap(-1)\n    .fillWeight(-1)\n    .stroke(.systemTeal)\n    .strokeWidth(2)\n    .curveTightness(0)\n    .curveStepCount(9)\n    .dashOffset(-1)\n    .dashGap(-1)\n    .zigzagOffset(-9)\n```\n\nThe beauty of `CALayer` is that we can further animate, transform (translate, scale, rotate) and compose them into more powerful shapes.\n\n## Options\n\n`Options` is used to custimize shape. It is immutable struct and apply to one shape at a time. The following properties are configurable\n\n- maxRandomnessOffset\n- toughness\n- bowing\n- fill\n- stroke\n- strokeWidth\n- curveTightness\n- curveStepCount\n- fillStyle\n- fillWeight\n- hachureAngle\n- hachureGap\n- dashOffset\n- dashGap\n- zigzagOffset\n\n## Shapes\n\nRoughSwift supports all primitive shapes, including SVG path\n\n- line\n- rectangle\n- ellipse\n- circle\n- linearPath\n- arc\n- curve\n- polygon\n- path\n\n## Fill style\n\nMost of the time, we use `fill` for solid fill color inside shape, `stroke` for shape border, and `fillStyle` for sketchy fill style.\n\nAvailable fill styles\n\n- crossHatch\n- dashed\n- dots\n- hachure\n- solid\n- starBurst\n- zigzag\n- zigzagLine\n\nHere's how to draw circles in different fill styles. The default fill style is hachure\n\n![](Screenshots/circles.png)\n\n```swift\nstruct StylesView: View {\n    var body: some View {\n        LazyVGrid(columns: [.init(), .init(), .init()], spacing: 12) {\n            RoughView()\n                .fill(.red)\n                .fillStyle(.crossHatch)\n                .circle()\n                .frame(width: 100, height: 100)\n\n            RoughView()\n                .fill(.green)\n                .fillStyle(.dashed)\n                .circle()\n                .frame(width: 100, height: 100)\n\n            RoughView()\n                .fill(.purple)\n                .fillStyle(.dots)\n                .circle()\n                .frame(width: 100, height: 100)\n\n            RoughView()\n                .fill(.cyan)\n                .fillStyle(.hachure)\n                .circle()\n                .frame(width: 100, height: 100)\n\n            RoughView()\n                .fill(.orange)\n                .fillStyle(.solid)\n                .circle()\n                .frame(width: 100, height: 100)\n\n            RoughView()\n                .fill(.gray)\n                .fillStyle(.starBurst)\n                .circle()\n                .frame(width: 100, height: 100)\n\n            RoughView()\n                .fill(.yellow)\n                .fillStyle(.zigzag)\n                .circle()\n                .frame(width: 100, height: 100)\n\n            RoughView()\n                .fill(.systemTeal)\n                .fillStyle(.zigzagLine)\n                .circle()\n                .frame(width: 100, height: 100)\n        }\n    }\n}\n```\n\n## SVG\n\n![](Screenshots/svg.png)\n\nSVG shape can be bigger or smaller than the specifed layer size, so RoughSwift scales them to your requested `size`. This way we can compose and transform the SVG shape.\n\n```swift\nstruct SVGView: View {\n    var apple: String {\n        \"M85 32C115 68 239 170 281 192 311 126 274 43 244 0c97 58 146 167 121 254 28 28 40 89 29 108 -25-45-67-39-93-24C176 409 24 296 0 233c68 56 170 65 226 27C165 217 56 89 36 54c42 38 116 96 161 122C159 137 108 72 85 32z\"\n    }\n\n    var body: some View {\n        VStack {\n            RoughView()\n                .stroke(.systemTeal)\n                .fill(.red)\n                .draw(Path(d: apple))\n                .frame(width: 300, height: 300)\n        }\n    }\n}\n```\n\n## Creative shapes\n\nWith all the primitive shapes, we can create more beautiful things. The only limit is your imagination.\n\nHere's how to create chart\n\n![](Screenshots/chart.png)\n\n```swift\nstruct Chartview: View {\n    var heights: [CGFloat] {\n        Array(0 ..\u003c 10).map { _ in CGFloat.random(in: 0 ..\u003c 150) }\n    }\n\n    var body: some View {\n        HStack {\n            ForEach(0 ..\u003c 10) { index in\n                VStack {\n                    Spacer()\n                    RoughView()\n                        .fill(.yellow)\n                        .rectangle()\n                        .frame(height: heights[index])\n                }\n            }\n        }\n        .padding(.horizontal)\n        .padding(.bottom, 100)\n    }\n}\n```\n\n\n## Advance with Drawable, Generator and Renderer\n\nBehind the screen, we composes `Generator` and `Renderer`. \n\nWe can instantiate `Engine` or use a shared `Engine` for memory efficiency, to make `Generator`. Every time we instruct `Generator` to draw a shape, the engine works hard to figure out information about the sketchy shape in `Drawable`.\n\nThe name of these concepts follow `rough.js` for better code reasoning.\n\nFor iOS, there is a `Renderer` that can handle `Drawable` and transform it into `UIBezierPath` and `CALayer`. There will be more `Renderer` that can render into graphics context, image and for other platforms like macOS and watchOS.\n\n\n```swift\nlet layer = CALayer()\nlet size = CGSize(width: 200, heigh: 200)\n\nlet renderer = Renderer(layer: layer)\nlet generator = Engine.shared.generator(size: bounds.size)\n\nlet drawable: Drawable = Rectangle(x: 10, y: 10, width: 100, height: 50)\nlet drawing = generate.generate(drawable: drawable)\n\nrenderer.render(drawing: drawing)\n```\n\n## Installation\n\nAdd the following line to the dependencies in your `Package.swift` file\n\n```swift\n.package(url: \"https://github.com/onmyway133/RoughSwift\"),\n```\n\n## Author\n\nKhoa Pham, onmyway133@gmail.com\n\n## Credit\n\n- [rough](https://github.com/pshihn/rough) for the generator that powers RoughSwift. All the hard work is done via rough in JavascriptCore.\n- [SVGPath](https://github.com/timrwood/SVGPath) for constructing UIBezierPath from SVG path\n\n## Contributing\n\nWe would love you to contribute to **RoughSwift**, check the [CONTRIBUTING](https://github.com/onmyway133/RoughSwift/blob/master/CONTRIBUTING.md) file for more info.\n\n## License\n\n**RoughSwift** is available under the MIT license. See the [LICENSE](https://github.com/onmyway133/RoughSwift/blob/master/LICENSE.md) file for more info.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fonmyway133%2Froughswift","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fonmyway133%2Froughswift","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fonmyway133%2Froughswift/lists"}