{"id":13816208,"url":"https://github.com/nwillc/ksvg","last_synced_at":"2026-01-12T13:46:33.242Z","repository":{"id":44996558,"uuid":"139922552","full_name":"nwillc/ksvg","owner":"nwillc","description":"A Multiplatform Kotlin SVG image DSL.","archived":false,"fork":false,"pushed_at":"2022-08-26T08:16:25.000Z","size":1084,"stargazers_count":80,"open_issues_count":9,"forks_count":16,"subscribers_count":3,"default_branch":"master","last_synced_at":"2024-11-19T13:37:37.622Z","etag":null,"topics":["dsl","kotlin","svg"],"latest_commit_sha":null,"homepage":"","language":"Kotlin","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"isc","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/nwillc.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-07-06T02:19:40.000Z","updated_at":"2024-11-19T07:06:37.000Z","dependencies_parsed_at":"2022-09-24T21:52:02.488Z","dependency_job_id":null,"html_url":"https://github.com/nwillc/ksvg","commit_stats":null,"previous_names":[],"tags_count":12,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nwillc%2Fksvg","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nwillc%2Fksvg/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nwillc%2Fksvg/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nwillc%2Fksvg/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nwillc","download_url":"https://codeload.github.com/nwillc/ksvg/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254367626,"owners_count":22059542,"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":["dsl","kotlin","svg"],"created_at":"2024-08-04T05:00:37.299Z","updated_at":"2026-01-12T13:46:32.926Z","avatar_url":"https://github.com/nwillc.png","language":"Kotlin","funding_links":[],"categories":["Kotlin"],"sub_categories":[],"readme":"[![Coverage](https://codecov.io/gh/nwillc/ksvg/branch/master/graphs/badge.svg?branch=master)](https://codecov.io/gh/nwillc/ksvg)\n[![license](https://img.shields.io/github/license/nwillc/ksvg.svg)](https://tldrlegal.com/license/-isc-license)\n[![Travis](https://img.shields.io/travis/nwillc/ksvg.svg)](https://travis-ci.org/nwillc/ksvg)\n[![Download](https://api.bintray.com/packages/nwillc/maven/ksvg/images/download.svg)](https://bintray.com/nwillc/maven/ksvg/_latestVersion)\n------\n\n# Kotlin Multiplatform SVG DSL\n\nI had a [Kotlin](https://kotlinlang.org/) microservice that needed to produce a simple heatmap chart on an HTML page to\na large audience very rapidly. This was an ad hoc DevOps requirement, so I didn't want to take on an involved Javascript\nsolution. Instead, I went with spitting out a half page of [inline SVG](https://www.w3schools.com/html/html5_svg.asp)\ntext generated by the server itself. This DSL made the server code trivial and has easily met the performance needs.\n\n## Installation\n\nThe library can be obtained from [JitPack.io](https://jitpack.io/#nwillc/ksvg).\n\nIn `build.gradle.kts`:\n\n```kotlin\nrepositories {\n    mavenCentral()\n    maven(\"https://jitpack.io\")\n}\n```\n\n```kotlin\nsourceSets {\n    commonMain {\n        dependencies {\n            implementation(\"com.github.nwillc.ksvg:ksvg:master-SNAPSHOT\")\n        }\n    }\n\n    val jvmMain by getting {\n        dependencies {\n            // No dependency required!\n        }\n    }\n\n    val jsMain by getting  {\n        dependencies {\n            // No dependency required!\n        }\n    }\n}\n```\n\n## Example\n\n```kotlin\n\nfun codeMonkey() {\n    val svg = SVG.svg(true) {\n         height = \"300\"\n         width = \"300\"\n         style {\n             body = \"\"\"\n\n                 svg .black-stroke { stroke: black; stroke-width: 2; }\n                 svg .fur-color { fill: white; }\n\n             \"\"\".trimIndent()\n         }\n         // Label\n         text {\n             x = \"40\"\n             y = \"50\"\n             body = \"#CODE\"\n             fontFamily = \"monospace\"\n             fontSize = \"40px\"\n         }\n         // Ears - example using a function because USE tag doesn't work in Safari\n         ear(100, 100)\n         ear(240, 70)\n         // Face\n         circle {\n             cssClass = \"black-stroke\"\n             id = \"face\"\n             cx = \"180\"\n             cy = \"140\"\n             r = \"80\"\n             fill = \"#aa450f\"\n         }\n         // Eyes\n         circle {\n             cssClass = \"black-stroke fur-color\"\n             id = \"eye\"\n             cx = \"160\"\n             cy = \"95\"\n             r = \"20\"\n         }\n         use {\n             x = \"45\"\n             y = \"-5\"\n             href = \"#eye\"\n         }\n         // Muzzle\n         circle {\n             cssClass = \"black-stroke fur-color\"\n             cx = \"195\"\n             cy = \"178\"\n             r = \"65\"\n         }\n         // Nostrils\n         circle {\n             id = \"nostril\"\n             cx = \"178\"\n             cy = \"138\"\n             r = \"4\"\n             fill = \"black\"\n         }\n         use {\n             x = \"35\"\n             y = \"-5\"\n             href = \"#nostril\"\n         }\n         // Mouth\n         path {\n             cssClass = \"black-stroke\"\n             d = \"M 150 150 C 100,250 305,260 230,140 C 205,190 165,170 150,150 Z\"\n             fill = \"red\"\n         }\n     }\n\n     FileWriter(\"build/tmp/codeMonkey.svg\").use {\n         svg.render(it, SVG.RenderMode.FILE)\n     }\n    }\n\n    private fun Container.ear(x: Int, y: Int) {\n        circle {\n            cssClass = \"black-stroke fur-color\"\n            cx = x.toString()\n            cy = y.toString()\n            r = \"40\"\n        }\n        circle {\n            cssClass = \"black-stroke fur-color\"\n            cx = x.toString()\n            cy = y.toString()\n            r = \"28\"\n        }\n    }\n\n```\nYields a code monkey:\n![code monkey](./docs/images/codeMonkey.svg)\n## Validation\nOriginally the attribute values were *appropriate* types, but eventually as support for percentage values etc. was\nadded, and considering they are always represented as strings in SVG, the value type was changed to String. But that\nmade errors like `length = \"foo\"` possible.  Therefore, attribute validation was added. Over time other validations\nbecame apparent too. With validation on, while the SVG is created, things are checked, for example when an attribute\nstring is assigned, if it can be properly validated, it is. Validation can be turned off for performance reasons.\n\n## About Inline vs File SVG\nSVG is an XML tag based format. Those tags can be put into an `.svg` file, or in modern browsers\nappear directly inline in the HTML5. However some attributes and other details differ slightly between these modes. This\nDSL is biased toward the inline representation because that's its origin, but it supports indicating the rendering mode\nand in the limitted scenarios tested it works.\n\n## A Limited Set of Elements\nCurrently only a small set of SVG Elements are supported. Adding more is straight forward, I just met my own needs, and\nso additions can be done by others, or as my needs increase.\n\n## Multiplatform Support\nThis is a multiplatform project currently targeting JVM and JavaScript.  The JVM target is fully baked, the\nJavaScript is still a bit doughy. Looking for JavaScript folks to help me polish it.\n\n## As Compared To kotlinx.html\nWhy did I write yet another SVG DSL when SVG is covered by the [kotlinx.html](https://github.com/Kotlin/kotlinx.html)?\nLet's just say ... you try using it. I could not figure out how to use it based on the SVG specification. This package\nis as close to a one to one mapping as I could make it.  So what if you want to combine them? Not a problem, just use\n`unsafe/raw`:\n\n```kotlin\n\n val svg = SVG.svg {\n   // ....\n }\n System.out.appendHTML().html {\n     body {\n        unsafe {\n            raw(svg.toString())\n        }\n     }\n }\n\n```\n\n## See Also\n\n- [API Docs](https://nwillc.github.io/ksvg/dokka/ksvg)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnwillc%2Fksvg","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnwillc%2Fksvg","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnwillc%2Fksvg/lists"}