{"id":17168386,"url":"https://github.com/apalala-dev/zwidget","last_synced_at":"2026-02-22T00:39:56.060Z","repository":{"id":56842153,"uuid":"469169855","full_name":"apalala-dev/zwidget","owner":"apalala-dev","description":"Simulate 3D effect by overlapping Widgets on top of each other","archived":false,"fork":false,"pushed_at":"2022-06-02T13:40:05.000Z","size":5347,"stargazers_count":14,"open_issues_count":1,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-06-15T08:53:57.476Z","etag":null,"topics":["3d","flutter","ui"],"latest_commit_sha":null,"homepage":"https://pub.dev/packages/zwidget","language":"Dart","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/apalala-dev.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","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":"2022-03-12T18:39:10.000Z","updated_at":"2025-01-04T01:49:46.000Z","dependencies_parsed_at":"2022-08-29T06:50:54.516Z","dependency_job_id":null,"html_url":"https://github.com/apalala-dev/zwidget","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/apalala-dev/zwidget","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/apalala-dev%2Fzwidget","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/apalala-dev%2Fzwidget/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/apalala-dev%2Fzwidget/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/apalala-dev%2Fzwidget/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/apalala-dev","download_url":"https://codeload.github.com/apalala-dev/zwidget/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/apalala-dev%2Fzwidget/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29701078,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-21T23:35:04.139Z","status":"ssl_error","status_checked_at":"2026-02-21T23:35:03.832Z","response_time":107,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":["3d","flutter","ui"],"created_at":"2024-10-14T23:11:49.353Z","updated_at":"2026-02-22T00:39:56.043Z","avatar_url":"https://github.com/apalala-dev.png","language":"Dart","funding_links":[],"categories":[],"sub_categories":[],"readme":"ZWidget creates a 3D-like visual by stacking widgets one above the other and transforming them adequately.\n\nThis package is heavily inspired by [ztext.js](https://bennettfeely.com/ztext/).\n\nSince Text is a Widget, and since everything is a Widget in Flutter, apply your 3D effect to any element of your UI!\n\nIt was created for the [Flutter Puzzle Hack](https://flutter.dev/events/puzzle-hack).\n\n## Features\n\nTilt your widgets and simulate 3D easily.\nHere are a few examples with `Text`, `FlutterLogo`, `Ìmage`, `Icon` and `CustomPaint`:\n\n![Various static examples](media/zwidget_various_examples.png)\n\nYou can also animate them:\n\n![Demo gif](media/zwidget_animated.gif)\n\nThe `example` project includes these demos and a few more.\n\n## Usage\n\nZWidget includes several constructors depending on the direction where you want your perspective effect to be.\n\n### ZWidget.backwards(), ZWidget.forwards() and ZWidget.bothDirections()\n\n![ZWidget direction constructors](media/zwidget_direction_constructors.png)\n\nYou must define at least the `midChild`, which is the base Widget that will be displayed.\nDepending on the direction you want the perspective to take place, you may also define the extremities and the widget to display between them and the middle child.\n\nHere is a full example for `ZWidget.bothDirections()`:\n\n``` dart\nZWidget.bothDirections(\n  // middle layer\n  midChild: Container(\n    width: 60,\n    height: 60,\n    color: Colors.blue,\n  ),\n  midToBotChild: Container(\n    width: 60,\n    height: 60,\n    color: Colors.blueGrey,\n  ),\n  // layers between mid and top child\n  midToTopChild: Container(\n    width: 60,\n    height: 60,\n    color: Colors.lightBlue,\n  ),\n  // layer at the bottom of the Stack\n  botChild: Container(\n    width: 60,\n    height: 60,\n    color: Colors.grey,\n  ),\n  // layer at the top of the Stack\n  topChild: Container(\n    width: 60,\n    height: 60,\n    color: Colors.lightBlueAccent,\n  ),\n  // rotation around X axis\n  rotationX: pi / 3,\n  // rotation around Y axis\n  rotationY: -pi / 4,\n  // Number of layers. Always odd (increased if even)\n  layers: 5,\n  // Space between layers\n  depth: 32,\n)\n```\n\n`ZWidget.backwards()` and `ZWidget.forwards()` are similar but they provide only the children parameters adequate to their direction.\n\nThe `layers` of a `ZWidget` are visibles in the picture below:\n\n![ZWidget layers](media/layers.png)\n\nThere is always an odd number of `layers`. If you define an even number, it will be increased to be an odd number. Increase `depth` to increase their spacing.\n\n`ZDirection` can be `forward`, `backward` or `both`.\n\nMid layer is the `midChild`. Depending on the `ZDirection`, other layers are displayed above or below the `midChild`.\nYou can define the `botChild` for the child at the bottom of the Stack and `topChild` for the one at the top.\nYou can also define Widgets between these extremities and `midChild` with `midToTopChild` and `midToBotChild`.\n\nUse the `alignment` property to set the `Transform` origin.\n\nTo effectively see the 3D effect, you must define a rotation to the ZWidget using `rotationX` and `rotationY`.\n\n### ZWidget.builder()\n\nIn case you would like to control which Widget is displayed at each layer, you may use `Widget.builder()`.\nIt can be used to make a gradient effect for instance.\n\nHere are a few examples:\n\n![ZWidget builder examples](media/zwidget_builder.png)\n\n\n\n### ZWidget()\n\nWhile the base `ZWidget` constructor works, it may lead newcomers to define parameters that are not needed.\nTherefore, it is now deprecated and you should use the other constructors instead.\n\n## Performance considerations\n\nIf ZWidget has 11 layers, it means that 11 Widgets will be drawn. Try to limit the complexity of widgets used at each layer.\n\nFor instance, an opaque Image could use simple Containers to simulate a 3D effect:\n\n```dart\n\nfinal child = ZWidget.forwards(\n  midChild: Container(\n    color: Colors.black,\n    // ...\n  ),\n  topChild: Image(\n    // ...\n  ),\n  rotationX: pi / 3,\n  rotationY: -pi / 4,\n  layers: 11,\n  depth: 16,\n);\n```\n\n## All parameters\n\n``` dart\n  // The builder function used to build each layer\n  final Widget Function(int) builder;\n  // Space between layers\n  final double depth;\n  // Perspective direction\n  final ZDirection direction;\n  // Rotation around X axis\n  final double rotationX;\n  // Rotation around Y axis\n  final double rotationY;\n  // Number of layers. Always odd (increased if set even)\n  final int layers;\n  // Experimental, used to reverse the X and Y rotations\n  final bool reverse;\n  // Shows a pink border representing the size taken by this `ZWidget`.\n  // Painting may go beyond that border.\n  final bool debug;\n  // The bigger the perspective, the more part of the widget will seem to be far away.\n  final double perspective;\n  // Transform origin\n  final Alignment? alignment;\n    // A fade effect (experimental)\n  final bool fade;\n```\n\n## ZWidget size\n\nDepending on the transformations and the 3D effect your want to achieve, your widget might be drawn beyond its limits.\n\nThe `debug` parameter shows a pink border around your `ZWidget` which indicates its layout size in the widget tree but the painting may go beyond that border.\n\nThat's because the `Transform` that we use doesn't change the base size of the widget, it just changes how it is rendered. The layout remains the same, but the painting can change a lot. See the `Transform` [documentation](https://api.flutter.dev/flutter/widgets/Transform-class.html) for more infos.\nYou might want to cut it to fit in the border with a `ClipRect` for instance.\n\n## How does it work?\n\nZWidget fills a Stack with `layers` Widgets returned by a `builder` function.\nThese are then transformed to make the 3D effect.\nThis transformations is done using a `Transform` widget and a `Matrix4`. If you'd like to do something similar but not with `Widget`, you can use the top-level function `zMatrix4()`.\n\n### zMatrix4\n\nThis method returns a `Matrix4` used to perform 3D transformations.\nYou can use it on anything accepting a `Matrix4` (Widget, Canvas, Path, ...).\n\n\n#### Widget example\n\n``` dart\nTransform(\n transform: zMatrix4(xTilt: pi / 3, yTilt: pi / 4, perspective: 5),\n child: Container(\n   color: Colors.red,\n   width: 100,\n   height: 100,\n ),\n);\n```\nZWidget uses `zMatrix4()` this way.\n\n#### Canvas example\n\n``` dart\ncanvas.transform(zMatrix4(xTilt: pi/3).storage);\n```\n\n#### Path example\n\n``` dart\nPath p = Path()\n ..addOval(Rect.fromCenter(\n      center: Offset(size.width / 2, size.height / 2),\n      width: size.width / 4,\n      height: size.height / 4))\n  ..transform(zMatrix4(xTilt: pi / 3).storage);\ncanvas.drawPath(p, Paint()..color = Colors.amber);\n```\n\n\n## Using this package\n\n- [ZPuzzle](https://play-zpuzzle.web.app)\n\nContact me if you are using this package and I will add you to the list!\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fapalala-dev%2Fzwidget","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fapalala-dev%2Fzwidget","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fapalala-dev%2Fzwidget/lists"}