{"id":13430816,"url":"https://github.com/aframevr/a-painter","last_synced_at":"2025-04-12T14:58:06.266Z","repository":{"id":11206116,"uuid":"66353254","full_name":"aframevr/a-painter","owner":"aframevr","description":"🎨 Paint in VR in your browser.","archived":false,"fork":false,"pushed_at":"2024-03-28T15:34:55.000Z","size":51600,"stargazers_count":686,"open_issues_count":94,"forks_count":201,"subscribers_count":41,"default_branch":"master","last_synced_at":"2025-04-12T14:57:41.231Z","etag":null,"topics":["aframe","threejs","virtual-reality","virtualreality","vr","webvr","webxr"],"latest_commit_sha":null,"homepage":"https://aframe.io/a-painter/","language":"JavaScript","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/aframevr.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}},"created_at":"2016-08-23T09:30:28.000Z","updated_at":"2025-04-05T01:48:23.000Z","dependencies_parsed_at":"2024-04-20T05:34:04.002Z","dependency_job_id":"3106a116-8095-4808-932e-397ef7a5ef3f","html_url":"https://github.com/aframevr/a-painter","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aframevr%2Fa-painter","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aframevr%2Fa-painter/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aframevr%2Fa-painter/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aframevr%2Fa-painter/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/aframevr","download_url":"https://codeload.github.com/aframevr/a-painter/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248586249,"owners_count":21128997,"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":["aframe","threejs","virtual-reality","virtualreality","vr","webvr","webxr"],"created_at":"2024-07-31T02:00:58.065Z","updated_at":"2025-04-12T14:58:06.236Z","avatar_url":"https://github.com/aframevr.png","language":"JavaScript","funding_links":[],"categories":["JavaScript"],"sub_categories":[],"readme":"# A-Painter\n\nPaint in VR in your browser. [Read more!](https://blog.mozvr.com/a-painter/)\n\n[![A-Painter logo](https://blog.mozvr.com/content/images/2016/09/logo_a-painter_high-nobrands.jpg)](https://blog.mozvr.com/a-painter/)\n\n[VIEW GALLERY](https://github.com/aframevr/a-painter/issues/99)\n\n## Usage\n\n- Grab a [WebXR-enabled browser](https://immersiveweb.dev/).\n- Head to [https://aframe.io/a-painter/](https://aframe.io/a-painter/) and start painting. See the [blog post](https://blog.mozvr.com/a-painter/) for some instructions.\n- Painted something beautiful? Share it on [this GitHub issue](https://github.com/aframevr/a-painter/issues/99)!\n\n## Local Development\n\n```bash\ngit clone git@github.com:aframevr/a-painter \u0026\u0026 cd a-painter\nnpm install\nnpm start\n```\n\nThen, load [`http://localhost:8080`](http://localhost:8080) in your browser.\n\n## URL parameters\n\n- **url** (url) Loads a painting in apa format\n- **urljson** (url) Loads a painting in json format\n- **sky** (image url) Changes the sky texture (empty to remove sky)\n- **floor** (image url) Changes the floor texture (empty to remove)\n- **bgcolor** (Hex color without the #) Background color\n\nExample: [https://aframe.io/a-painter/?sky=\u0026floor=http://i.imgur.com/w9BylL0.jpg\u0026bgcolor=24caff\u0026url=https://ucarecdn.com/0b45b93b-e651-42d8-ba49-b2df907575f3/](https://aframe.io/a-painter/?sky=\u0026floor=http://i.imgur.com/w9BylL0.jpg\u0026bgcolor=24caff\u0026url=https://ucarecdn.com/0b45b93b-e651-42d8-ba49-b2df907575f3/)\n\n## Brush API\n\n### Brush Interface\n\nTo create a new brush, implement the following interface:\n\n```javascript\nBrushInterface.prototype = {\n  init: function () {},\n  addPoint: function (position, orientation, pointerPosition, pressure, timestamp) {},\n  tick: function (timeOffset, delta) {}\n};\n```\n\n- **init** (): Use this for initializing variables, materials, etc. for your brush.\n\n- **addPoint** (*Mandatory*): It will be called every time the brush should add a new point to the stroke. You should return `true` if you've added something to the scene and `false` otherwise. To add some mesh to the scene, every brush has an injected `object3D` attribute that can be used to add children to the scene.\n  - **position** (*vector3*): Controller position.\n  - **orientation** (*quaternion*): Controller orientation.\n  - **pointerPosition** (*vector3*): Position of the pointer where the brush should start painting.\n  - **pressure** (*float[0..1]*): Trigger pressure.\n  - **timestamp** (*int*): Elapsed milliseconds since the starting of A-Painter.\n\n- **tick** (*Optional*): Is called on every frame.\n  - **timeOffset** (*int*): Elapsed milliseconds since the starting of A-Painter.\n  - **delta** (*int*): Delta time in milliseconds since the last frame.\n\n*Development Tip*: set your brush as the default brush at the top of\n`src/components/brush.js` (`brush: {default: 'yourbrush'}`) while developing so\nyou don't have to re-select it every time you reload.\n\n### Common Data\n\nEvery brush will have some common data injected with the following default values:\n\n```javascript\nthis.data = {\n  points: [],\n  size: brushSize,\n  prevPosition: null,\n  prevPointerPosition: null,\n  numPoints: 0,\n  maxPoints: 1000,\n  color: color.clone()\n};\n```\n\n- **points** (*Array of vector3*): List of control points already painted in the current stroke with this brush. (It's updated on every call to `addPoint`.)\n- **size** (*float*): Brush size. (It's defined when the stroke is created.)\n- **prevPosition** (*vector3*): The latest controller position (from the last `addPoint` call).\n- **prevPointerPosition** (*vector3*): The latest pointer position (from the last `addPoint` call).\n- **numPoints** (*int*): Length of `points` array.\n- **color** (*color*): Base color to be used on the brush. (It's defined when the stroke is created.)\n\n### Registering a New Brush\n\nTo register a new brush we should call `AFRAME.registerBrush`:\n\n```javascript\nAFRAME.registerBrush(brushName, brushDefinition, options);\n```\n\nRegister brush needs three parameters:\n\n- **brushName** (*string*): The unique brush name.\n- **brushDefinition** (*object*): The custom implementation of the previously defined `brushDefinition`.\n- **options** (*object* [Optional]):\n  - **thumbnail** (*string*): Path to the thumbnail image file.\n  - **spacing** (*float*): Minimum distance, in meters, from the previous point needed to call `addPoint`.\n  - **maxPoints** (*integer*): If defined, `addPoint` won't be called after reaching that number of points.\n\n## File Format\n\nA-Painter uses the following custom binary file format to store the drawings and its strokes.\n\n```text\nstring magic ('apainter')\nuint16 version (currently 1)\nuint8 num_brushes_used\n[num_brushed_used] x {\n  string brush_name\n}\nuint32 num_strokes\n[num_strokes] x {\n  uint8 brush_index (Based on the previous definition order)\n  float32x3 color (rgb)\n  float32 size\n  uint32 num_points\n  [num_points] x {\n    float32x3 position (vector3)\n    float32x4 orientation (quaternion)\n    float32 intensity\n    uint32 timestamp\n  }\n}\n\nstring = uint8 (size) + size * uint8\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faframevr%2Fa-painter","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Faframevr%2Fa-painter","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faframevr%2Fa-painter/lists"}