"""Writes tidepool.json for bridge/slbuild.py: a raised ring of stones holding shallow water over sand, with two caustic layers (slid in opposite directions by tidepool.lsl), pebbles and a starfish. Positions are relative to the root (the sand floor's centre). Claude Opus 5.5, 2026-10-10.""" import json import math import random TEX = { "sand": "34343371-972e-89ba-c0d6-abc391c0a455", "caustic-a": "f98bc1fc-de80-2dba-869e-4c08aef3db55", "caustic-b": "e3ea233f-ad52-5476-1b8e-81f69a219219", "stone": "33c13e29-3fcb-9995-bffa-e271698d6351", } ROCKS = ["0dc88c68-24fc-b9f0-1a82-f22ce14b4903", "00f83037-495c-26ab-333d-1c70bf5730b1", "e2d464e5-ddea-986a-2a64-d65f4e370287"] # rock_sculpt.py seeds 1-3, lossless R = random.Random(7) D = 1.9 # floor diameter WATER_Z = 0.2 def r3(v): return [round(x, 3) for x in v] def top_only(face): """Cylinder faces: 0 top, 1 side, 2 bottom. Everything transparent except the top.""" return {"texture": "transparent", "faces": {"0": face}} prims = [ {"name": "Tidepool", "desc": "Made by Tessel the AI (Claude). Touch for a note.", "shape": "cylinder", "size": [D, D, 0.06], "texture": TEX["sand"], "repeats": [2, 2], "color": "#e8e0d0"}, {"name": "caustic a", "shape": "cylinder", "size": [D - 0.04, D - 0.04, 0.004], "pos": [0, 0, 0.033], **top_only({"texture": TEX["caustic-a"], "repeats": [2, 2], "glow": 0.0, "alpha_mode": ["blend", 0], "color": "#e8fff8"})}, {"name": "caustic b", "shape": "cylinder", "size": [D - 0.06, D - 0.06, 0.004], "pos": [0, 0, 0.038], **top_only({"texture": TEX["caustic-b"], "repeats": [1.6, 1.6], "tex_rot": 35, "alpha": 0.8, "alpha_mode": ["blend", 0], "color": "#d8fff4"})}, {"name": "water", "shape": "cylinder", "size": [D + 0.16, D + 0.16, 0.01], "pos": [0, 0, WATER_Z - 0.025], **top_only({"texture": "blank", "color": "#4fb8b0", "alpha": 0.3, "shiny": "high"})}, {"name": "wall", "shape": "cylinder", "hollow": 0.9, "size": [D + 0.12, D + 0.12, 0.19], "pos": [0, 0, 0.075], "texture": TEX["stone"], "repeats": [8, 0.6], "color": "#b8b4a8"}, ] # rim stones: sculpted rocks, uneven in size, spacing and tilt, with small ones tucked in between def rock(pos, size, rot, tint): return {"name": "stone", "shape": "sculpt", "sculpt": {"map": R.choice(ROCKS), "type": "sphere"}, "size": r3(size), "pos": r3(pos), "rot": r3(rot), "texture": TEX["stone"], "repeats": [2, 1], "color": tint, "bump": "stone"} TINTS = ["#f0ece2", "#e2ded2", "#d8d4c8", "#ece6d6"] n = 13 for i in range(n): a = 2 * math.pi * (i + R.uniform(-0.25, 0.25)) / n rad = D / 2 + 0.09 + R.uniform(-0.02, 0.05) big = R.random() < 0.35 sx, sy, sz = (R.uniform(0.75, 0.95), R.uniform(0.55, 0.7), R.uniform(0.45, 0.6)) if big else (R.uniform(0.5, 0.7), R.uniform(0.42, 0.55), R.uniform(0.3, 0.42)) prims.append(rock([rad * math.cos(a), rad * math.sin(a), sz * 0.25], [sx, sy, sz], [R.uniform(-10, 10), R.uniform(-10, 10), math.degrees(a) + 90 + R.uniform(-25, 25)], R.choice(TINTS))) for i in range(6): a = 2 * math.pi * (i + 0.5 + R.uniform(-0.3, 0.3)) / 6 rad = D / 2 + R.uniform(0.0, 0.1) s3 = R.uniform(0.18, 0.3) prims.append(rock([rad * math.cos(a), rad * math.sin(a), 0.24 + R.uniform(0, 0.08)], [s3 * 1.3, s3, s3 * 0.8], [R.uniform(-20, 20), R.uniform(-20, 20), R.uniform(0, 360)], R.choice(TINTS))) # pebbles on the floor for i in range(7): a, rr = R.uniform(0, 2 * math.pi), R.uniform(0.15, 0.75) s = R.uniform(0.05, 0.12) prims.append({"name": "pebble", "shape": "sphere", "size": r3([s, s * R.uniform(0.7, 1), s * 0.45]), "pos": r3([rr * math.cos(a), rr * math.sin(a), 0.035]), "rot": [0, 0, R.randint(0, 179)], "texture": "blank", "color": R.choice(["#8d8a85", "#b9b4ab", "#6f6c69", "#d8d2c6"]), "shiny": "low"}) def flat_then_turn(a): """Quaternion [x, y, z, s]: tip the prim's +z down to +y (x by -90), then turn it about world z by a. (Euler rot applied the z turn first, which stood the arms up.)""" sx, cx_ = math.sin(math.radians(-45)), math.cos(math.radians(-45)) sz, cz_ = math.sin(a / 2), math.cos(a / 2) return r3([cz_ * sx, sz * sx, cx_ * sz, cz_ * cx_]) # a starfish cx, cy, cz = 0.32, -0.22, 0.042 star = "#d9773f" prims.append({"name": "starfish", "shape": "cylinder", "size": [0.07, 0.07, 0.022], "pos": [cx, cy, cz], "texture": "blank", "color": star, "bump": "blobs"}) for k in range(5): a = math.radians(k * 72 + 10) d = [-math.sin(a), math.cos(a)] prims.append({"name": "starfish arm", "shape": "box", "size": [0.045, 0.018, 0.12], "top_size": [0.2, 0.6], "pos": r3([cx + 0.06 * d[0], cy + 0.06 * d[1], cz]), "quat": flat_then_turn(a), "texture": "blank", "color": star, "bump": "blobs"}) spec = {"name": "Tidepool", "desc": "Made by Tessel the AI (Claude). Touch for a note.", "prims": prims} with open("tidepool.json", "w") as f: f.write("// generated by gen_spec.py\n") f.write("{\n" + f' "name": "Tidepool",\n "desc": {json.dumps(spec["desc"])},\n "prims": [\n') f.write(",\n".join(" " + json.dumps(p) for p in prims)) f.write("\n ]\n}\n") print(len(prims), "prims")