{"id":17217840,"url":"https://github.com/fzipp/canvas","last_synced_at":"2025-10-20T05:48:03.323Z","repository":{"id":43844981,"uuid":"296100140","full_name":"fzipp/canvas","owner":"fzipp","description":"Draw on an HTML 2D canvas in a web browser from a server program using WebSockets.","archived":false,"fork":false,"pushed_at":"2025-02-24T06:48:17.000Z","size":599,"stargazers_count":92,"open_issues_count":1,"forks_count":13,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-03-30T02:05:40.416Z","etag":null,"topics":["2d","2d-graphics","canvas","canvas-api","canvas2d","drawing","go","golang","graphics","websockets"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/fzipp.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,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-09-16T17:19:35.000Z","updated_at":"2025-03-09T17:05:11.000Z","dependencies_parsed_at":"2024-04-27T05:29:43.065Z","dependency_job_id":"3008844c-bf3f-485a-a188-38d306aa53a0","html_url":"https://github.com/fzipp/canvas","commit_stats":{"total_commits":162,"total_committers":2,"mean_commits":81.0,"dds":0.01851851851851849,"last_synced_commit":"aac9add1705c672e20047104818b4b40187f6f92"},"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fzipp%2Fcanvas","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fzipp%2Fcanvas/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fzipp%2Fcanvas/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fzipp%2Fcanvas/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/fzipp","download_url":"https://codeload.github.com/fzipp/canvas/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247427006,"owners_count":20937201,"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":["2d","2d-graphics","canvas","canvas-api","canvas2d","drawing","go","golang","graphics","websockets"],"created_at":"2024-10-15T03:44:49.457Z","updated_at":"2025-10-20T05:47:58.271Z","avatar_url":"https://github.com/fzipp.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# canvas\n\n[![PkgGoDev](https://pkg.go.dev/badge/github.com/fzipp/canvas)](https://pkg.go.dev/github.com/fzipp/canvas)\n![Build Status](https://github.com/fzipp/canvas/workflows/build/badge.svg)\n[![Go Report Card](https://goreportcard.com/badge/github.com/fzipp/canvas)](https://goreportcard.com/report/github.com/fzipp/canvas)\n\nThis Go module utilizes WebSockets to establish communication with a\n[2D canvas graphics context](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D)\nin a web browser,\nproviding a portable way to create interactive 2D graphics\nfrom within a Go program.\n\nThe Go program (server) sends draw commands to the web browser (client)\nvia WebSocket using a binary format.\nIn return, the client sends keyboard, mouse, and touch events to the server.\n\nThis module does not rely on operating system-specific backends\nor Cgo bindings.\nIt also does not utilize WebAssembly,\nwhich means the Go code runs on the server side,\nrather than in the browser.\nThe client-server design enables the canvas\nto be displayed on a different machine over the network.\n\n## Examples\n\nThe [example](example) subdirectory contains a variety of demo programs.\n\n![Screenshots of examples](https://github.com/fzipp/canvas/blob/assets/examples.png)\n\n## Usage\n\n### Drawing\n\nThe `ListenAndServe` function initializes the canvas server\nand takes the following arguments:\nthe network address with the port number to bind to,\na run function,\nand an options structure that configures various aspects\nsuch as the canvas size in pixels\nor a title for the browser tab.\n\nThe `run` function is called when a client connects to the server.\nThis serves as the entry point for drawing.\n\n```go\npackage main\n\nimport (\n\t\"image/color\"\n\t\"log\"\n\n\t\"github.com/fzipp/canvas\"\n)\n\nfunc main() {\n\terr := canvas.ListenAndServe(\":8080\", run, \u0026canvas.Options{\n\t\tTitle:  \"Example 1: Drawing\",\n\t\tWidth:  100,\n\t\tHeight: 80,\n\t})\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n}\n\nfunc run(ctx *canvas.Context) {\n\tctx.SetFillStyle(color.RGBA{R: 200, A: 255})\n\tctx.FillRect(10, 10, 50, 50)\n\t// ...\n\tctx.Flush()\n}\n```\n\nAfter starting the program,\nyou can access the canvas by opening http://localhost:8080\nin a web browser.\n\nThe server doesn't immediately send each drawing operation to the client\nbut instead buffers them until the `Flush` method is called.\nThe flush should occur once the image or an animation frame is complete;\notherwise, nothing will be displayed.\n\nEach client connection starts its own run function as a goroutine.\nAccess to shared state between client connections must be synchronized.\nIf you don't want to share state between connections,\nyou should keep it local to the run function\nand pass the state to other functions called by the run function.\n\n### An animation loop\n\nTo create an animation,\nyou can use a `for` loop within the `run` function.\nInside this loop,\nobserve the `ctx.Events()` channel\nfor a `canvas.CloseEvent` to exit the loop\nwhen the connection is closed.\n\nA useful pattern is to create a struct\nthat holds the animation state\nand has both an update and a draw method:\n\n```go\npackage main\n\nimport (\n\t\"log\"\n\t\"time\"\n\n\t\"github.com/fzipp/canvas\"\n)\n\nfunc main() {\n\terr := canvas.ListenAndServe(\":8080\", run, \u0026canvas.Options{\n\t\tTitle:  \"Example 2: Animation\",\n\t\tWidth:  800,\n\t\tHeight: 600,\n\t})\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n}\n\nfunc run(ctx *canvas.Context) {\n\td := \u0026demo{}\n\tfor {\n\t\tselect {\n\t\tcase event := \u003c-ctx.Events():\n\t\t\tif _, ok := event.(canvas.CloseEvent); ok {\n\t\t\t\treturn\n\t\t\t}\n\t\tdefault:\n\t\t\td.update()\n\t\t\td.draw(ctx)\n\t\t\tctx.Flush()\n\t\t\ttime.Sleep(time.Second / 6)\n\t\t}\n\t}\n}\n\ntype demo struct {\n\t// Animation state, for example:\n\tx, y int\n\t// ...\n}\n\nfunc (d *demo) update() {\n\t// Update animation state for the next frame\n\t// ...\n}\n\nfunc (d *demo) draw(ctx *canvas.Context) {\n\t// Draw the frame here, based on the animation state\n\t// ...\n}\n```\n\n### Keyboard, mouse and touch events\n\nTo handle keyboard, mouse, and touch events,\nyou need to specify which events the client should observe\nand send to the server.\nThis is achieved by passing an `EnabledEvents` option\nto the `ListenAndServe` function.\nMouse move events typically generate more WebSocket communication\nthan the others,\nso you may want to enable them only if necessary.\n\nThe `ctx.Events()` channel receives the observed events,\nand a type switch is used to determine the specific event type.\nA useful pattern involves creating a `handle` method for event handling:\n\n```go\npackage main\n\nimport (\n\t\"log\"\n\n\t\"github.com/fzipp/canvas\"\n)\n\nfunc main() {\n\terr := canvas.ListenAndServe(\":8080\", run, \u0026canvas.Options{\n\t\tTitle:  \"Example 3: Events\",\n\t\tWidth:  800,\n\t\tHeight: 600,\n\t\tEnabledEvents: []canvas.Event{\n\t\t\tcanvas.MouseDownEvent{},\n\t\t\tcanvas.MouseMoveEvent{},\n\t\t\tcanvas.TouchStartEvent{},\n\t\t\tcanvas.TouchMoveEvent{},\n\t\t\tcanvas.KeyDownEvent{},\n\t\t},\n\t})\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n}\n\nfunc run(ctx *canvas.Context) {\n\td := \u0026demo{}\n\tfor !d.quit {\n\t\tselect {\n\t\tcase event := \u003c-ctx.Events():\n\t\t\td.handle(event)\n\t\tdefault:\n\t\t\td.update()\n\t\t\td.draw(ctx)\n\t\t\tctx.Flush()\n\t\t}\n\t}\n}\n\ntype demo struct {\n\tquit bool\n\t// ...\n}\n\nfunc (d *demo) handle(event canvas.Event) {\n\tswitch e := event.(type) {\n\tcase canvas.CloseEvent:\n\t\td.quit = true\n\tcase canvas.MouseDownEvent:\n\t\t// ...\n\tcase canvas.MouseMoveEvent:\n\t\t// ...\n\tcase canvas.TouchStartEvent:\n\t\t// ...\n   \tcase canvas.TouchMoveEvent:\n\t\t// ...\n   \tcase canvas.KeyDownEvent:\n\t\t// ...\n\t}\n}\n\nfunc (d *demo) update() {\n\t// ...\n}\n\nfunc (d *demo) draw(ctx *canvas.Context) {\n\t// ...\n}\n```\n\nNote that the `canvas.CloseEvent` does not have to be explicitly enabled.\nIt is always enabled by default.\n\n## Alternatives\n\n* [github.com/tfriedel6/canvas](https://github.com/tfriedel6/canvas) -\n  A canvas implementation for Go with OpenGL backends for various\n  operating systems.\n* [github.com/llgcode/draw2d](https://github.com/llgcode/draw2d) -\n  A 2D vector graphics library for Go with support for multiple outputs\n  such as images, PDF documents, OpenGL and SVG.\n* [github.com/ajstarks/svgo](https://github.com/ajstarks/svgo) -\n  A Go library for SVG generation.\n* [github.com/tdewolff/canvas](https://github.com/tdewolff/canvas) -\n  A common vector drawing target that can output SVG, PDF, EPS,\n  raster images (PNG, JPG, GIF, ...), HTML Canvas through WASM, and OpenGL.\n* [github.com/fogleman/gg](https://github.com/fogleman/gg) -\n  A library for rendering 2D graphics in pure Go.\n\n2D game engines:\n\n* [github.com/faiface/pixel](https://github.com/faiface/pixel) - Pixel\n* [github.com/hajimehoshi/ebiten](https://github.com/hajimehoshi/ebiten) - Ebiten\n* [github.com/oakmound/oak](https://github.com/oakmound/oak) - Oak\n\n## License\n\nThis project is free and open source software licensed under the\n[BSD 3-Clause License](LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffzipp%2Fcanvas","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffzipp%2Fcanvas","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffzipp%2Fcanvas/lists"}