{ "cells": [ { "cell_type": "code", "execution_count": null, "id": "b5072f85-b264-4470-a61b-e703b06fc7c5", "metadata": {}, "outputs": [], "source": [ "# File: roller.ipynb\n", "# Code: Claude Code and Codex\n", "# Review: Ryoichi Ando (ryoichi.ando@zozo.com)\n", "# License: Apache v2.0" ] }, { "cell_type": "code", "execution_count": null, "id": "509bdf6f-125f-46d9-b99c-79fdd80b3926", "metadata": {}, "outputs": [], "source": [ "from frontend import App\n", "\n", "# create an app\n", "app = App.create(\"roller\")\n", "\n", "# create a cylinder mesh for rollers\n", "r, half_l = 0.15, 0.7\n", "V, F = app.mesh.cylinder(r=r, min_x=-half_l, max_x=half_l, n=40)\n", "app.asset.add.tri(\"cylinder\", V, F)\n", "\n", "# create a knot tetrahedral mesh\n", "V, F, T = app.mesh.preset(\"knot\").tetrahedralize().normalize()\n", "app.asset.add.tet(\"knot\", V, F, T)\n", "\n", "# create a scene\n", "scene = app.scene.create()\n", "\n", "# add knot object with friction\n", "obj = scene.add(\"knot\").scale(0.6).at(0, 0.4, 0).jitter().rotate(270, \"y\")\n", "obj.param.set(\"friction\", 0.5)\n", "\n", "# add invisible floor\n", "scene.add.invisible.wall([0, -1, 0], [0, 1, 0])\n", "\n", "# create two pairs of counter-rotating rollers to flatten the knot\n", "half_gap, left, right = 1.1 * r, [], []\n", "left.append(scene.add(\"cylinder\").rotate(90, \"y\").at(-half_gap, 0, 0))\n", "left.append(scene.add(\"cylinder\").rotate(90, \"y\").at(-half_gap, -2 * half_gap, 0))\n", "right.append(scene.add(\"cylinder\").rotate(90, \"y\").at(half_gap, 0, 0))\n", "right.append(scene.add(\"cylinder\").rotate(90, \"y\").at(half_gap, -2 * half_gap, 0))\n", "\n", "# set spinning motion for rollers\n", "w = 360.0\n", "for obj in left:\n", " obj.pin().spin(axis=[0, 0, -1], angular_velocity=w)\n", "for obj in right:\n", " obj.pin().spin(axis=[0, 0, 1], angular_velocity=w)\n", "\n", "# set directional coloring for all rollers\n", "for obj in left + right:\n", " obj.direction_color(1, 0, 0)\n", "\n", "# set preview options\n", "opts = {\n", " \"pin\": False,\n", " \"wireframe\": True,\n", " \"lookat\": [0, -0.25, 0],\n", " \"eye\": [0, 0.5, 2.5],\n", " \"fov\": 55,\n", "}\n", "\n", "# compile the scene and report stats\n", "scene = scene.build().report()\n", "\n", "# preview the initial scene\n", "scene.preview(options=opts)" ] }, { "cell_type": "code", "execution_count": null, "id": "bace491d-1f73-4602-a2e0-b89a83fabdda", "metadata": {}, "outputs": [], "source": [ "# create a new session with the compiled scene\n", "session = app.session.create(scene)\n", "\n", "# set session parameters\n", "session.param.set(\"frames\", 180).set(\"friction-mode\", \"max\")\n", "\n", "# build this session\n", "session = session.build()" ] }, { "cell_type": "code", "execution_count": null, "id": "5eba74ef-0373-4d8f-98b3-4609ebcb474a", "metadata": {}, "outputs": [], "source": [ "# start the simulation and live-preview the results\n", "session.start().preview(options=opts)\n", "\n", "# also show simulation logs in realtime\n", "session.stream()" ] }, { "cell_type": "code", "execution_count": null, "id": "fdfb20af-5c02-4cfa-850e-89d568594f72", "metadata": {}, "outputs": [], "source": [ "# create an animation from the simulation results\n", "session.animate(options=opts)" ] }, { "cell_type": "code", "execution_count": null, "id": "907a2929-0a51-4b44-8b66-8498284dc259", "metadata": {}, "outputs": [], "source": [ "# export the animation to file\n", "session.export.animation()" ] }, { "cell_type": "code", "execution_count": null, "id": "2f4bd160-a8dc-4476-8429-33269b03a037", "metadata": {}, "outputs": [], "source": [ "# this is for CI\n", "if app.ci:\n", " assert session.finished()" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.12.3" } }, "nbformat": 4, "nbformat_minor": 5 }