A shot-by-shot 15-second, 16:9 hand-drawn anime prompt that animates an 8-frame storyboard: a girl cycles through summer rice fields past a wind chime to a riverbank, sips lemon soda and watches a local train cross a bridge before a rising aerial reveal, with timed shots, countryside-only sound design, energy arc and consistency rules. Trending on X, originally shared by @HeyAbhishek: https://x.com/HeyAbhishek/status/2115429393967550598
TITLE THE SUMMER DETOUR Create a 15-second cinematic nostalgic anime animation in 16:9 landscape format. REFERENCE Use the uploaded storyboard as the main visual reference. Follow its 8 shots in order. Keep the girl, bicycle, clothes, soda bottle, rice fields, river, train, and sunlight consistent throughout. Do not add characters, change locations unexpectedly, or introduce fantasy elements. SUBJECTS Girl: Original 13-year-old Japanese girl with shoulder-length dark brown hair, brown eyes, cream blouse, faded navy skirt, white socks, brown shoes, and canvas shoulder bag. Bicycle: Vintage mint-green city bicycle with a silver handlebar, brown saddle, front wire basket, and black tires. Props: One clear glass lemon soda bottle, initially in the basket and later held by the girl. Train: Small cream-and-orange two-car local passenger train. ENVIRONMENT Peaceful Japanese countryside in late summer. Narrow roads, bright green rice paddies, traditional wooden houses, hanging wind chimes, grassy riverbanks, distant railway bridge, green mountains, and large white summer clouds. Warm late-afternoon sunlight with gentle natural shadows. No sunset or dramatic lighting changes. STYLE Premium cinematic 2D anime with beautiful hand-painted backgrounds, soft cel shading, clean linework, natural colors, gentle environmental animation, and expressive but restrained character acting. Create a calm, nostalgic feeling of an ordinary childhood summer afternoon. Avoid photorealism, 3D CGI, neon lighting, excessive effects, and artificial camera movement. AUDIO No music or dialogue. Natural countryside ambience only: cicadas, birds, soft wind, bicycle wheels, wind chimes, flowing river water, soda bottle sounds, and a distant passing train. Keep the soundscape gentle, atmospheric, and continuous. CAMERA AND FRAMING 16:9 cinematic framing. Smooth tracking shots, intimate close-ups, slow camera movements, and beautiful landscape compositions. Use natural shot transitions and consistent sunlight. SHOT-BY-SHOT TIMELINE SHOT 1 (00:00-00:01.5) - THE SUMMER ROAD Wide cinematic shot of a peaceful countryside road surrounded by lush rice fields. The girl pedals her mint-green bicycle slowly toward the distant mountains. Her hair moves gently in the warm breeze. Camera tracks smoothly behind her. SFX: cicadas, gentle wind, bicycle tires. SHOT 2 (00:01.5-00:03) - LITTLE DETAILS Low close-up beside the bicycle. The wheels turn smoothly as sunlight flickers between the spokes. Tall grass and tiny wildflowers sway along the roadside. Camera follows the moving wheels with shallow depth of field. SFX: rolling tires, grass rustling, summer insects. SHOT 3 (00:03-00:05) - THE OPEN FIELDS Beautiful side-tracking shot of the girl cycling beside endless green rice paddies. Enormous fluffy white clouds drift slowly above the distant mountains. Her skirt and hair move naturally in the breeze. Bright sunlight fills the landscape. SFX: wind through rice fields, distant birds, bicycle chain. SHOT 4 (00:05-00:06.5) - THE WIND CHIME The girl cycles past a small traditional wooden house. Camera briefly follows a glass wind chime hanging beneath the roof as it sways gently. Sunlight reflects through the glass while the girl continues down the road in the background. SFX: delicate wind chime, cicadas, soft bicycle movement. SHOT 5 (00:06.5-00:08.5) - THE RIVERBANK Wide shot of a quiet grassy riverbank. The girl arrives, stops her bicycle beside a shady tree, lowers its kickstand, and sits down on the grass. Sunlight sparkles across the flowing river. Camera slowly moves closer. SFX: bicycle stopping, soft footsteps, flowing water. SHOT 6 (00:08.5-00:10) - A SUMMER SIP Intimate medium close-up. The girl takes the lemon soda bottle from her bicycle basket, opens it, and takes a refreshing sip while sitting in the grass. Tiny bubbles rise through the clear glass. She smiles peacefully. SFX: bottle opening, gentle fizz, summer breeze. SHOT 7 (00:10-00:12) - THE PASSING TRAIN Cinematic medium-wide shot from behind the girl's shoulder. A cream-and-orange local train travels slowly across the distant railway bridge above the river. The girl watches quietly as sunlight glows across the passing carriages. SFX: soft distant train wheels, river water, cicadas. SHOT 8 (00:12-00:15) - THE SUMMER MEMORY (SIGNATURE MOMENT) The camera slowly rises above the grassy riverbank into a magnificent aerial panorama. Reveal the winding blue river, endless green rice paddies, scattered countryside houses, distant mountains, and the small train continuing across the bridge. The girl remains a tiny peaceful figure beside her parked bicycle beneath the tree. The huge blue summer sky and beautiful white clouds dominate the final composition. Camera movement gradually slows and settles into a breathtaking wide shot. Hold until the end. SFX: warm countryside breeze, distant train fading away, gentle cicadas. ENERGY ARC Act 1 (0-5s): Freedom. Slow cycling, warm sunlight, peaceful summer landscapes. Act 2 (5-10s): Stillness. Wind chimes, riverbank, a quiet moment with cold soda. Act 3 (10-15s): Nostalgia. Passing train, expansive countryside reveal, and a peaceful ending. FINAL REQUIREMENTS Maintain consistent character proportions, outfit, bicycle design, train appearance, and geography. Use smooth hand-drawn anime motion, believable cycling physics, gentle wind animation, and natural water movement. No additional people, duplicated objects, character morphing, flickering, subtitles, logos, text overlays, or watermarks. The final video should feel like a beautiful, soothing memory of a summer afternoon.

A single-image anime pre-production board for an original 15-second short: a character design sheet (turnarounds, expressions, poses) of a girl and her mint-green bicycle plus an 8-frame cinematic storyboard of a summer ride through Japanese rice fields to a riverbank and a passing train, ready to feed into a video model. Trending on X, originally shared by @HeyAbhishek: https://x.com/HeyAbhishek/status/2115429393967550598
Create one vertical anime development board for an original 15-second short film titled "The Summer Detour". The output must be one combined image with 2 sections: Character design sheet Cinematic storyboard page STYLE: Beautiful nostalgic 2D anime, hand-painted countryside backgrounds, clean anime linework, soft cel shading, lush green scenery, warm summer afternoon sunlight, gentle shadows, and bright blue skies with fluffy clouds. Professional anime production board with red storyboard borders, blue camera arrows, small handwritten camera notes, and beautifully illustrated keyframes. SECTION A: CHARACTER DESIGN Main girl: An original 13-year-old Japanese girl with shoulder-length dark brown hair, soft brown eyes, and a gentle, cheerful expression. Outfit: cream short-sleeved blouse, faded navy skirt, white socks, brown shoes, and a small canvas shoulder bag. Personality: calm, curious, thoughtful, and quietly happy. Show front, side, three-quarter, and back views, plus smiling, thoughtful, relaxed, and surprised expressions. Include cycling, sitting, and looking toward the horizon poses. BICYCLE: Vintage mint-green city bicycle with a silver handlebar, brown saddle, small front wire basket, and simple black tires. A clear glass bottle of lemon soda sits securely inside the basket. Keep the bicycle's design consistent in every frame. SECTION B: STORYBOARD Create 8 storyboard frames in a clean grid, each using 16:9 cinematic framing. Keep the girl, bicycle, countryside, and lighting consistent. Story beats: Wide opening shot of the girl cycling along a peaceful countryside road surrounded by green rice fields. Beautiful close-up of bicycle wheels turning beside swaying grass, sunlight sparkling through the spokes. Side-tracking shot as she cycles past expansive rice paddies beneath enormous fluffy summer clouds. She passes a small traditional house with hanging wind chimes gently swaying in the breeze. She reaches a quiet grassy riverbank, stops, and parks her bicycle beside a tree. Sitting in the grass, she opens her cold lemon soda and takes a refreshing sip. A small cream-and-orange local train crosses a distant bridge over the river. She watches it with a gentle smile. Spectacular wide ending shot: the camera rises to reveal the winding river, endless green fields, distant mountains, passing train, and girl resting beside her bicycle under a magnificent summer sky. ENVIRONMENT: Peaceful rural Japanese countryside, vibrant rice paddies, narrow asphalt roads, traditional wooden houses, wind chimes, wildflowers, a clear river, an old railway bridge, distant green mountains, and beautiful summer clouds. Bright late-afternoon sunlight throughout. FINAL GOAL: Create a beautiful nostalgic anime film development board with soothing countryside scenery, authentic everyday moments, natural cinematic movement, consistent character design, and a breathtaking peaceful ending.
Finds fair meeting times for distributed teams. Takes each participant's IANA time zone, working days and hours, how far they will stretch, holidays and blocked time, then lists every slot in a date range in each person's local time, handles daylight-saving switches that happen on different weekends, and picks a rotating series so the same people do not always take the early or late call. Includes a stdlib Python zoneinfo script with --self-test.
---
name: time-zone-meeting-slot-finder
description: Finds fair meeting times for distributed teams. Takes each participant's IANA time zone, working days and hours, how far they will stretch, holidays and blocked time, then lists every slot in a date range in each person's local time, handles daylight-saving switches that happen on different weekends, and picks a rotating series so the same people do not always take the early or late call. Includes a stdlib Python zoneinfo script with --self-test.
---
# Time Zone Meeting Slot Finder
You help distributed teams pick meeting times that are possible for everyone required and fair over time. You work in each person's own local time on the actual dates (never with "LA is 9 hours behind Berlin" rules of thumb, which are wrong for weeks every spring and autumn), show the trade-offs openly, and rotate the inconvenient slots instead of always putting them on the same people.
## Files in this skill
- `scripts/slot_finder.py` - reads a team CSV and optional blocked-time CSV, evaluates every slot on a grid over the date range in each participant's local time (Python zoneinfo), ranks slots by who is missing and how much stretch they need, reports DST changes in the range, and can pick a fair rotating series (Python 3.9+ standard library only)
- `references/dst-and-time-zone-pitfalls.md` - DST dates by region, zones that do not switch, half-hour zones, weekends that are not Sat-Sun, abbreviations to avoid, and how calendar invites behave across a switch
- `references/fairness-and-rotation.md` - the pain-point model, how the rotation chooses, when to split a meeting or go async instead, and how to explain the choice to the team
- `templates/slot-proposal.md` - the proposal to send to the team
- `examples/team.csv` - five people in Los Angeles, New York, Berlin, Istanbul and Kolkata (one optional)
- `examples/blocked.csv` - a public holiday, a dentist appointment, a board review and a day of leave
## Workflow
### 1. Collect the facts
For each participant: name, IANA zone (city based, e.g. `America/Los_Angeles`, never "PST"), working days (Mon-Fri, or Sun-Thu in much of the Middle East), working hours, how many hours they are willing to start earlier or finish later, and whether they are required. Also the date range, meeting length, how often it repeats, known holidays and blocked times (in that person's local time). Ask rather than guess zones from a city that has several (e.g. a "Mexico" team member).
### 2. Run the finder
```
python3 scripts/slot_finder.py --team examples/team.csv --blocked examples/blocked.csv --start 2026-10-26 --end 2026-11-20 --days Tue,Wed,Thu --series 4
python3 scripts/slot_finder.py --team team.csv --start 2026-11-02 --end 2026-11-06 --duration 30 --step 15 --top 5
python3 scripts/slot_finder.py --team team.csv --start 2026-11-02 --end 2026-11-27 --series 8 --every day --ref-zone Europe/Berlin --json
python3 scripts/slot_finder.py --self-test
```
Dates (`--start`, `--end`, `--days`) are read in `--ref-zone` (default UTC). Exit 0 means slots were found, 1 means no slot works for every required person, 2 means bad input (unknown zone, bad time, missing column).
### 3. Read the result
- **DST changes in range** come first: if any zone switches inside the range, the same UTC time lands an hour earlier or later for those people afterwards. Propose slots per period, not one UTC time for the whole range.
- **Best slots** are ranked by: optional people missing, then the worst single person's stretch, then total stretch.
- **Rotating series** picks one meeting per week (or per day) to keep the worst cumulative inconvenience as low as possible, then spreads it. The summary shows how often each person met in hours, stretched or missed.
- If there is no slot, say why (who blocks whom) and offer options: more stretch from volunteers, a shorter meeting, making someone optional, two regional meetings, or async updates.
### 4. Deliver
Fill `templates/slot-proposal.md`: the recommendation with every person's local time and weekday, the DST note, the rotation table, alternatives, and the open questions. Send invites from a calendar with a real zone (the organizer's IANA zone), not "UTC" unless the team agreed, and say which zone anchors the series.
## Example result
Five people, 2026-10-26 to 2026-11-20, Tue-Thu, 60 minutes, series of 4 weekly meetings. Europe left summer time on 25 October and the US on 1 November, so in the week of 26 October New York is only 5 hours behind Berlin instead of 6. Week 1: 13:30 UTC (Ana 06:30 in Los Angeles, a stretch; Priya 19:00 in Kolkata, a stretch; everyone else in hours). After the US change, two weeks at 16:00 UTC (Ana 08:00 in hours, Eva 17:00-18:00 stretch, Bilal 19:00-20:00 stretch) and one at 14:30 UTC (Ana stretches again). Bilal is blocked on 29 October (Republic Day). Priya (optional, +05:30) can join only before the US change; the proposal adds a recorded summary for her and suggests an Asia-friendly slot once a month.
## Rules
- Always use IANA zone names and compute local times per date; never apply fixed offsets across a DST boundary.
- Show every participant's local time and weekday for each proposal, since the date can differ (Kolkata evening, Los Angeles morning).
- Nobody is scheduled outside the stretch they agreed to; ask before assuming someone will take a 06:00 or 22:00 call.
- Rotate inconvenience and show the tally; if one person always loses, say so and suggest a structural fix (split, async, rotate the meeting owner).
- Respect weekends, public holidays and blocked time in the person's own calendar and zone.
- Keep the recommendation short; put the full table in an appendix.
FILE:references/dst-and-time-zone-pitfalls.md
# DST and time zone pitfalls
## Use IANA zone names
- `America/New_York`, `Europe/Berlin`, `Asia/Kolkata`, `Australia/Sydney`. They carry the full history and future rules of that region.
- Avoid abbreviations: "EST", "CST", "IST" and "BST" are ambiguous (IST = India, Ireland or Israel; CST = US Central, China or Cuba) and the zoneinfo entries named EST or MST are fixed offsets with no DST. The script warns on names without a "/".
- Avoid fixed offsets like UTC+1 for people: offsets change twice a year in many places.
- Pick the city that shares the person's rules: Arizona (`America/Phoenix`) has no DST; most of Mexico dropped DST in 2022; `America/Sao_Paulo` dropped DST in 2019.
- Keep the zone database current (`tzdata`); governments change rules with a few weeks' notice.
## DST dates (2026, check each year)
| Region | Summer time starts | Ends | Note |
|---|---|---|---|
| US and Canada (most) | 2nd Sunday of March (2026-03-08) | 1st Sunday of November (2026-11-01) | local 02:00 |
| EU, UK | last Sunday of March (2026-03-29) | last Sunday of October (2026-10-25) | 01:00 UTC, all at once |
| Australia (south-east), New Zealand | first Sunday of October / last Sunday of September | first Sunday of April | southern hemisphere: opposite season |
| No DST | Turkey (UTC+3), India (+05:30), China, Japan, Singapore, UAE, most of Africa, Arizona | | |
So there are two "gap" periods each year when the US-Europe difference is one hour smaller than usual: about 3 weeks in March and 1 week at the end of October / start of November. Recurring meetings anchored in one region move by an hour for the other during those weeks.
## Offsets that are not whole hours
- India +05:30, Iran +03:30, Nepal +05:45, Newfoundland -03:30 (-02:30 in summer), South Australia +09:30/+10:30, Chatham Islands +12:45. A grid on the hour in UTC lands on :30 or :45 for these people; the script evaluates in 5-minute chunks so these are exact.
## Weekends and working days
- Sun-Thu working weeks: e.g. Israel; Fri-Sat weekends in several Gulf countries, while the UAE moved to Mon-Fri (with a half Friday) in 2022. Ask each person.
- Public holidays differ per country and per region (Bavaria vs Berlin, US states). Add them to the blocked file in local dates.
- A Monday 08:00 slot in Los Angeles is Monday evening in India but already Tuesday morning in Sydney or Auckland. Always show the weekday per person.
## DST on the switch day itself
- Spring forward: local times between 02:00 and 03:00 (US) do not exist; autumn back: 01:00-02:00 happens twice. Avoid scheduling in those hours on switch days; the script works on UTC instants so it never produces an invalid time, but humans reading "01:30" on that day can be confused.
## Calendar invites across a switch
- A recurring invite is anchored to the organizer's zone. A 10:00 New York weekly meeting stays at 10:00 in New York and moves for Berlin during the gap weeks.
- If the series must stay fair for both sides, anchor it in UTC deliberately and tell everyone, or plan the gap weeks explicitly.
- Check the invite's zone after creating it (some tools default to the device zone or to "floating" time).
FILE:references/fairness-and-rotation.md
# Fairness and rotation
## Pain-point model used by the script
| Situation for one person in one meeting | Points |
|---|---|
| Entirely inside their working hours | 0 |
| Partly or fully in their stretch window (before or after work, as much as they agreed to) | 2 per hour of stretch, pro rata (30 min = 1) |
| Outside the stretch window, on a non-working day, or during blocked time | cannot attend (slot invalid if they are required) |
| Optional person who cannot attend (rotation tally only) | 3 |
Ranking of single slots: fewest optional people missing, then the lowest worst-off person, then the lowest total.
Rotation (`--series N`): greedily adds one meeting at a time, at most one per ISO week (`--every week`, default) or per date (`--every day`), choosing the slot that keeps the highest cumulative score lowest, then the sum of squared cumulative scores (which spreads pain instead of concentrating it), then fewer people missing. The summary table shows per person: meetings in hours, stretched, missed, total points.
The weights are a model, not a truth. Adjust them with the team: an early start may cost a parent more than a late finish, a 22:00 call costs more than 18:30. Change stretch windows per person to reflect what they actually accept.
## Make the trade-offs visible
- Show each person's local time and weekday for each option.
- Show the rotation tally, so that "Bilal stretches 3 of 4 times" is a visible decision, not an accident.
- Ask people to set their own stretch windows; never assume someone will take a 06:30 call because they did it once.
## When no fair slot exists
- Shorten the meeting: 30 minutes often fits where 60 does not.
- Make people optional and record the meeting with written notes and a decision log.
- Split by region (Americas + Europe, Europe + Asia) with one person bridging, and rotate the bridge.
- Alternate two time slots week by week (e.g. 14:00 UTC and 07:00 UTC) so each side gets the convenient one half the time.
- Go async: written updates, recorded demos, decisions in a doc with a deadline in everyone's local time.
## Checklist before sending
- Every required person is in hours or in their agreed stretch for every meeting in the series.
- Holidays and leave in each country are in the blocked file.
- DST changes in the range are named, and the series accounts for them.
- The invite is created in the agreed anchor zone; times in the message are given per person.
- There is a review date (e.g. after the next DST change) to rotate again.
FILE:templates/slot-proposal.md
# Meeting time proposal: <meeting name>
**Who:** <Ana (Los Angeles), Dana (New York), Eva (Berlin), Bilal (Istanbul), Priya (Kolkata, optional)>
**Length / cadence:** <60 min weekly, Tue-Thu> **Range checked:** <2026-10-26 to 2026-11-20>
**Anchor zone for the invite:** <UTC / organizer's zone>
## Recommendation
| Week | Start (UTC) | Ana | Dana | Eva | Bilal | Priya |
|---|---|---|---|---|---|---|
| <Oct 26> | <Tue 13:30> | <Tue 06:30 (stretch)> | <09:30> | <14:30> | <16:30> | <19:00 (stretch)> |
| <Nov 2> | <Wed 16:00> | <08:00> | <11:00> | <17:00 (stretch)> | <19:00 (stretch)> | <cannot (21:30)> |
## Daylight saving
- <Europe left summer time on Oct 25, the US on Nov 1: during the week of Oct 26 New York is 5 h behind Berlin instead of 6, so the slot moves by an hour from Nov 2>
## Fairness over the series
| Name | In hours | Stretch | Missed | Points |
|---|---|---|---|---|
| <Ana> | <2> | <2> | <0> | <4> |
<One sentence on who carries the most and what we do about it (e.g. Priya: recorded summary + an Asia-friendly slot monthly).>
## Alternatives
1. <30-minute version at 15:00 UTC: everyone in hours except ...>
2. <alternate two slots week by week>
## Blocked dates taken into account
- <Oct 29: Republic Day, Turkey (Bilal)>
## Please confirm
- <your stretch window is still right>
- <holidays or leave in this range we missed>
FILE:examples/team.csv
name,zone,work_start,work_end,days,flex_before,flex_after,required
Ana,America/Los_Angeles,08:00,16:30,Mon-Fri,1.5,1,yes
Dana,America/New_York,08:30,17:00,Mon-Fri,1,1,yes
Eva,Europe/Berlin,09:00,17:30,Mon-Fri,1,1.5,yes
Bilal,Europe/Istanbul,09:00,18:00,Mon-Fri,0,2,yes
Priya,Asia/Kolkata,10:00,18:30,Mon-Fri,0,2,no
FILE:examples/blocked.csv
name,date,start,end,reason
Bilal,2026-10-29,,,Republic Day (public holiday in Turkey)
Dana,2026-11-03,10:00,11:30,dentist
Eva,2026-11-05,15:30,17:30,quarterly board review
Priya,2026-11-06,,,leave
FILE:scripts/slot_finder.py
#!/usr/bin/env python3
"""Time zone meeting slot finder (Python 3.9+ standard library: zoneinfo).
Given participants with IANA time zones, working days and hours (plus how far each one
is willing to stretch before or after work), finds meeting slots over a date range,
ranks them by fairness, and can pick a rotating series so the same people do not take
the early or late call every time. Each slot is evaluated in every participant's own
local time on that date, so daylight-saving transitions inside the range (Europe and
the US switch on different weekends) are handled automatically and reported.
Pain points per participant and meeting: 0 inside working hours, 2 per hour inside the
stretch ("flex") window before or after work, unavailable beyond that, on non-working
days or during blocked time. Missing an optional participant counts as 3 pain points
for them in the rotation tally.
Usage:
python3 slot_finder.py --team team.csv --start 2026-10-26 --end 2026-11-06
[--duration 60] [--step 30] [--blocked blocked.csv] [--days Tue,Wed,Thu]
[--ref-zone UTC] [--top 10] [--series N [--every week|day]] [--json]
python3 slot_finder.py --self-test
team.csv columns: name, zone, work_start, work_end, days (Mon-Fri or Sun-Thu or
Mon,Wed,Fri), flex_before, flex_after (hours, optional), required (yes/no, optional).
work_end earlier than work_start means a shift that runs past midnight.
blocked.csv columns: name, date (participant's local date), start, end (empty = all day), reason.
Exit codes: 0 = slots found, 1 = no slot where all required participants can attend,
2 = bad input (unknown time zone, bad time, missing file or column).
"""
import argparse, csv, datetime as dt, io, json, sys
from zoneinfo import ZoneInfo, ZoneInfoNotFoundError
DAY_NAMES = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]
CHUNK = 5 # minutes; fine enough for +05:30 and +05:45 zones
FLEX_PAIN_PER_HOUR = 2
MISSED_PAIN = 3
class InputError(Exception):
pass
def parse_days(s):
s = (s or "Mon-Fri").strip()
out = set()
for part in s.replace(" ", "").split(","):
if not part:
continue
if "-" in part:
a, b = part.split("-", 1)
i, j = day_index(a), day_index(b)
k = i
while True:
out.add(k)
if k == j:
break
k = (k + 1) % 7
else:
out.add(day_index(part))
return out
def day_index(name):
n = name.strip()[:3].title()
if n not in DAY_NAMES:
raise InputError(f"unknown day '{name}' (use Mon..Sun)")
return DAY_NAMES.index(n)
def parse_hm(s, what):
try:
h, m = s.strip().split(":")
h, m = int(h), int(m)
if not (0 <= h <= 24 and 0 <= m < 60) or (h == 24 and m):
raise ValueError
return h * 60 + m
except (ValueError, AttributeError):
raise InputError(f"bad time '{s}' for {what} (use HH:MM, 24-hour)")
def load_zone(name, who, warnings):
name = (name or "").strip()
try:
z = ZoneInfo(name)
except (ZoneInfoNotFoundError, ValueError):
raise InputError(f"unknown time zone '{name}' for {who}: use an IANA name such as America/New_York, Europe/Berlin, Asia/Kolkata (pip install tzdata if the system has no zone database)")
if "/" not in name and name not in ("UTC", "Etc/UTC"):
warnings.append(f"{who}: '{name}' is an abbreviation or legacy zone with fixed rules; use the city-based IANA name (e.g. America/New_York, not EST) so daylight saving is right")
return z
def read_team(text, warnings):
rows = list(csv.DictReader(io.StringIO(text.lstrip("\ufeff"))))
if not rows:
raise InputError("team file has no rows")
for col in ("name", "zone", "work_start", "work_end"):
if col not in rows[0]:
raise InputError(f"team file is missing column '{col}'")
team = []
for r in rows:
who = (r.get("name") or "").strip()
if not who:
continue
p = {"name": who, "zone_name": r["zone"].strip(), "zone": load_zone(r["zone"], who, warnings),
"start": parse_hm(r["work_start"], who + " work_start"), "end": parse_hm(r["work_end"], who + " work_end"),
"days": parse_days(r.get("days")),
"flex_before": int(round(float(r.get("flex_before") or 0) * 60)),
"flex_after": int(round(float(r.get("flex_after") or 0) * 60)),
"required": (r.get("required") or "yes").strip().lower() not in ("no", "n", "false", "0", "optional"),
"blocked": []}
if p["start"] == p["end"]:
raise InputError(f"{who}: work_start equals work_end")
team.append(p)
names = [p["name"] for p in team]
if len(set(names)) != len(names):
raise InputError("duplicate participant names in team file")
return team
def read_blocked(text, team):
byname = {p["name"].lower(): p for p in team}
for r in csv.DictReader(io.StringIO(text.lstrip("\ufeff"))):
who = (r.get("name") or "").strip()
if not who:
continue
p = byname.get(who.lower())
if not p:
raise InputError(f"blocked time for unknown participant '{who}'")
try:
d = dt.date.fromisoformat(r["date"].strip())
except (ValueError, KeyError):
raise InputError(f"bad date in blocked file for {who}: {r.get('date')}")
s, e = (r.get("start") or "").strip(), (r.get("end") or "").strip()
a = dt.datetime.combine(d, dt.time()) + dt.timedelta(minutes=parse_hm(s, who + " blocked start") if s else 0)
b = dt.datetime.combine(d, dt.time()) + dt.timedelta(minutes=parse_hm(e, who + " blocked end") if e else 1440)
p["blocked"].append((a, b, (r.get("reason") or "").strip()))
def classify(p, local):
"""local: naive local datetime. Return 'core', 'flex' or None (unavailable)."""
best = None
for back in (0, 1):
d = local.date() - dt.timedelta(days=back)
if d.weekday() not in p["days"]:
continue
base = dt.datetime.combine(d, dt.time())
cs = base + dt.timedelta(minutes=p["start"])
ce = base + dt.timedelta(minutes=p["end"] + (1440 if p["end"] <= p["start"] else 0))
if cs <= local < ce:
return "core"
if cs - dt.timedelta(minutes=p["flex_before"]) <= local < ce + dt.timedelta(minutes=p["flex_after"]):
best = "flex"
return best
def evaluate(p, start_utc, minutes):
"""Return (status, pain, local_start, local_end, reason). status in core, flex, out."""
flex_min = 0
reason = ""
for k in range(0, minutes, CHUNK):
t = (start_utc + dt.timedelta(minutes=k)).astimezone(p["zone"]).replace(tzinfo=None)
c = classify(p, t)
if c is None:
reason = "outside hours" if t.date().weekday() in p["days"] or classify_day_any(p, t) else "day off"
return "out", 0.0, *local_span(p, start_utc, minutes), reason
for a, b, why in p["blocked"]:
if a <= t < b:
return "out", 0.0, *local_span(p, start_utc, minutes), f"blocked: {why}" if why else "blocked"
if c == "flex":
flex_min += CHUNK
pain = round(flex_min / 60 * FLEX_PAIN_PER_HOUR, 2)
return ("flex" if flex_min else "core"), pain, *local_span(p, start_utc, minutes), ""
def classify_day_any(p, t):
return (t.date() - dt.timedelta(days=1)).weekday() in p["days"] and p["end"] <= p["start"]
def local_span(p, start_utc, minutes):
a = start_utc.astimezone(p["zone"])
b = (start_utc + dt.timedelta(minutes=minutes)).astimezone(p["zone"])
return a, b
def dst_changes(team, start, end):
out = []
seen = set()
for p in team:
if p["zone_name"] in seen:
continue
seen.add(p["zone_name"])
z = p["zone"]
t = dt.datetime.combine(start - dt.timedelta(days=1), dt.time(), tzinfo=dt.timezone.utc)
stop = dt.datetime.combine(end + dt.timedelta(days=2), dt.time(), tzinfo=dt.timezone.utc)
prev = t.astimezone(z).utcoffset()
while t < stop:
t2 = t + dt.timedelta(minutes=30)
off = t2.astimezone(z).utcoffset()
if off != prev:
loc = t2.astimezone(z)
out.append({"zone": p["zone_name"], "utc": t2.strftime("%Y-%m-%d %H:%M UTC"),
"local": loc.strftime("%Y-%m-%d %H:%M %Z"), "from": fmt_off(prev), "to": fmt_off(off)})
prev = off
t = t2
return out
def fmt_off(td):
m = int(td.total_seconds() // 60)
s = "+" if m >= 0 else "-"
m = abs(m)
return f"UTC{s}{m // 60:02d}:{m % 60:02d}"
def find_slots(team, start, end, duration, step, ref_zone, only_days=None):
"""start/end: dates in ref_zone (inclusive). Returns list of slot dicts."""
slots = []
t = dt.datetime.combine(start, dt.time(), tzinfo=ref_zone).astimezone(dt.timezone.utc)
stop = dt.datetime.combine(end + dt.timedelta(days=1), dt.time(), tzinfo=ref_zone).astimezone(dt.timezone.utc)
t = t.replace(minute=(t.minute // step) * step if step < 60 else 0, second=0, microsecond=0)
while t + dt.timedelta(minutes=duration) <= stop:
ref_local = t.astimezone(ref_zone)
if only_days is None or ref_local.weekday() in only_days:
per, ok = {}, True
for p in team:
st, pain, a, b, why = evaluate(p, t, duration)
per[p["name"]] = {"status": st, "pain": pain, "local_start": a, "local_end": b, "reason": why}
if st == "out" and p["required"]:
ok = False
break
if ok:
missing = [p["name"] for p in team if per[p["name"]]["status"] == "out"]
pains = [per[p["name"]]["pain"] for p in team]
slots.append({"utc": t, "per": per, "missing": missing, "total_pain": round(sum(pains), 2),
"max_pain": max(pains)})
t += dt.timedelta(minutes=step)
return slots
def rank(slots):
return sorted(slots, key=lambda s: (len(s["missing"]), s["max_pain"], s["total_pain"], s["utc"]))
def period_key(s, ref_zone, every):
d = s["utc"].astimezone(ref_zone).date()
return d.isocalendar()[:2] if every == "week" else d
def pick_series(slots, team, n, ref_zone, every="week"):
"""Greedy fair rotation: n slots, at most one per ref-zone ISO week (every="week") or
per date (every="day"), minimising the worst cumulative pain, then the sum of squared
cumulative pain, then missed people."""
cum = {p["name"]: 0.0 for p in team}
chosen, used_dates = [], set()
for _ in range(n):
best, best_key = None, None
for s in slots:
d = period_key(s, ref_zone, every)
if d in used_dates:
continue
new = {k: cum[k] + (MISSED_PAIN if s["per"][k]["status"] == "out" else s["per"][k]["pain"]) for k in cum}
key = (round(max(new.values()), 2), round(sum(v * v for v in new.values()), 2), len(s["missing"]), s["total_pain"], s["utc"])
if best_key is None or key < best_key:
best, best_key = s, key
if best is None:
break
chosen.append(best)
used_dates.add(period_key(best, ref_zone, every))
for k in cum:
cum[k] += MISSED_PAIN if best["per"][k]["status"] == "out" else best["per"][k]["pain"]
chosen.sort(key=lambda s: s["utc"])
return chosen, cum
def cell(info):
a, b = info["local_start"], info["local_end"]
txt = f"{DAY_NAMES[a.weekday()]} {a:%H:%M}-{b:%H:%M}"
if info["status"] == "flex":
txt += f" (stretch, {info['pain']:g})"
elif info["status"] == "out":
txt += f" (cannot: {info['reason']})"
return txt
def table(slots, team, ref_zone):
head = ["#", f"Start ({ref_zone.key})"] + [f"{p['name']} ({p['zone_name']})" for p in team] + ["Pain total/max", "Missing"]
out = ["| " + " | ".join(head) + " |", "|" + "---|" * len(head)]
for i, s in enumerate(slots, 1):
r = s["utc"].astimezone(ref_zone)
row = [str(i), f"{DAY_NAMES[r.weekday()]} {r:%Y-%m-%d %H:%M}"] + [cell(s["per"][p["name"]]) for p in team] + \
[f"{s['total_pain']:g}/{s['max_pain']:g}", ", ".join(s["missing"]) or "-"]
out.append("| " + " | ".join(row) + " |")
return out
def report(team, slots, args, ref_zone, warnings, changes, series=None, cum=None):
out = [f"# Meeting slots {args['start']} to {args['end']} ({args['duration']} min, dates in {ref_zone.key})", ""]
for w in warnings:
out.append(f"> WARNING: {w}")
if warnings:
out.append("")
out.append("## Participants")
out.append("| Name | Zone | Hours (local) | Days | Stretch before/after | Required |")
out.append("|---|---|---|---|---|---|")
for p in team:
days = ",".join(DAY_NAMES[d] for d in sorted(p["days"]))
out.append(f"| {p['name']} | {p['zone_name']} | {p['start'] // 60:02d}:{p['start'] % 60:02d}-{p['end'] // 60:02d}:{p['end'] % 60:02d} | {days} | {p['flex_before'] / 60:g}h / {p['flex_after'] / 60:g}h | {'yes' if p['required'] else 'no'} |")
out += ["", "## Daylight saving changes in range"]
if changes:
for c in changes:
out.append(f"- {c['zone']}: {c['from']} -> {c['to']} at {c['local']} ({c['utc']}); the same UTC time moves by an hour locally after this")
else:
out.append("- none")
out.append("")
if not slots:
out.append("No slot found where every required participant is available. Options: allow more stretch hours, make someone optional, shorten the meeting, split into two regional meetings, or go async.")
return "\n".join(out)
if series:
out += [f"## Rotating series ({len(series)} meetings, fairest combination found by greedy rotation)", ""] + table(series, team, ref_zone)
out += ["", "| Name | In hours | Stretch | Missed | Pain total |", "|---|---|---|---|---|"]
for p in team:
st = [s["per"][p["name"]]["status"] for s in series]
out.append(f"| {p['name']} | {st.count('core')} | {st.count('flex')} | {st.count('out')} | {cum[p['name']]:g} |")
out.append("")
top = rank(slots)[:args["top"]]
out += [f"## Best {len(top)} of {len(slots)} possible slots", ""] + table(top, team, ref_zone)
out += ["", f"Pain: 0 inside working hours, {FLEX_PAIN_PER_HOUR} per hour of stretch, {MISSED_PAIN} for an optional person who cannot attend (rotation only)."]
return "\n".join(out)
def to_json(team, slots, series, cum, changes, warnings, ref_zone, top):
def enc(s):
return {"start_utc": s["utc"].strftime("%Y-%m-%dT%H:%MZ"), "start_ref": s["utc"].astimezone(ref_zone).isoformat(),
"total_pain": s["total_pain"], "max_pain": s["max_pain"], "missing": s["missing"],
"participants": {k: {"status": v["status"], "pain": v["pain"], "local_start": v["local_start"].isoformat(),
"local_end": v["local_end"].isoformat(), "reason": v["reason"]} for k, v in s["per"].items()}}
return {"warnings": warnings, "dst_changes": changes, "slot_count": len(slots),
"best": [enc(s) for s in rank(slots)[:top]], "series": [enc(s) for s in series or []], "series_pain": cum or {}}
def run(team_text, start, end, duration=60, step=30, blocked_text=None, ref="UTC", top=10, series=0, only_days=None, every="week"):
warnings = []
team = read_team(team_text, warnings)
if blocked_text:
read_blocked(blocked_text, team)
ref_zone = load_zone(ref, "--ref-zone", warnings)
if end < start:
raise InputError("--end is before --start")
if duration % CHUNK or step % CHUNK or duration <= 0 or step <= 0:
raise InputError(f"--duration and --step must be positive multiples of {CHUNK} minutes")
slots = find_slots(team, start, end, duration, step, ref_zone, only_days)
chosen, cum = pick_series(slots, team, series, ref_zone, every) if series else (None, None)
changes = dst_changes(team, start, end)
return team, slots, chosen, cum, changes, warnings, ref_zone
def self_test():
T = "name,zone,work_start,work_end,days,flex_before,flex_after,required\n"
D = dt.date
passed, total = 0, 0
def check(name, cond):
nonlocal passed, total
total += 1
passed += bool(cond)
print(("PASS " if cond else "FAIL ") + name)
team, slots, *_ = run(T + "A,Europe/Berlin,09:00,17:00,Mon-Fri,0,0,yes\nB,Europe/London,09:00,17:00,Mon-Fri,0,0,yes\n", D(2026, 11, 2), D(2026, 11, 2))
check("Berlin+London overlap is 09:00-16:00 UTC (13 one-hour starts on the 30-min grid)", len(slots) == 13 and slots[0]["utc"].hour == 9 and slots[-1]["utc"].hour == 15)
check("all in-hours slots have zero pain", all(s["total_pain"] == 0 for s in slots))
team, slots, *_ = run(T + "A,America/Los_Angeles,09:00,17:00,Mon-Fri,0,0,yes\nB,Asia/Kolkata,09:00,18:00,Mon-Fri,0,0,yes\n", D(2026, 11, 2), D(2026, 11, 6))
check("LA and Kolkata without stretch: no slot", not slots)
team, slots, *_ = run(T + "A,America/Los_Angeles,09:00,17:00,Mon-Fri,2,0,yes\nB,Asia/Kolkata,09:00,18:00,Mon-Fri,0,3,yes\n", D(2026, 11, 2), D(2026, 11, 6), duration=30)
check("with 2h/3h stretch: only 30-min slots (15:00 UTC) exist and all carry pain", slots and all(s["total_pain"] > 0 for s in slots))
s0 = rank(slots)[0]
check("half-hour zone: Kolkata local minutes end in :30", s0["per"]["B"]["local_start"].minute == 30)
team, slots, *_ = run(T + "A,Europe/Berlin,09:00,17:00,Mon-Fri,0,0,yes\nB,America/New_York,09:00,17:00,Mon-Fri,0,0,yes\n", D(2026, 10, 26), D(2026, 10, 26))
first = slots[0]["utc"]
check("Berlin-NY in the gap week (EU back on CET, US still EDT): overlap 13:00-16:00 UTC", first.hour == 13 and slots[-1]["utc"].hour == 15)
team, slots2, *_ = run(T + "A,Europe/Berlin,09:00,17:00,Mon-Fri,0,0,yes\nB,America/New_York,09:00,17:00,Mon-Fri,0,0,yes\n", D(2026, 11, 2), D(2026, 11, 2))
check("after US DST end: overlap starts 14:00 UTC", slots2[0]["utc"].hour == 14)
*_, changes, w, rz = run(T + "A,Europe/Berlin,09:00,17:00,Mon-Fri,0,0,yes\nB,America/New_York,09:00,17:00,Mon-Fri,0,0,yes\n", D(2026, 10, 24), D(2026, 11, 3))
zones = {c["zone"]: c for c in changes}
check("DST changes found: Berlin 2026-10-25 and New York 2026-11-01", "2026-10-25" in zones.get("Europe/Berlin", {}).get("local", "") and "2026-11-01" in zones.get("America/New_York", {}).get("local", ""))
team, slots, *_ = run(T + "A,Asia/Dubai,09:00,17:00,Sun-Thu,0,0,yes\nB,Europe/London,09:00,17:00,Mon-Fri,0,0,yes\n", D(2026, 11, 6), D(2026, 11, 8))
check("Sun-Thu vs Mon-Fri: no Fri/Sat/Sun slot", not slots)
team, slots, *_ = run(T + "A,Asia/Dubai,09:00,17:00,Sun-Thu,0,0,yes\nB,Europe/London,09:00,17:00,Mon-Fri,0,0,yes\n", D(2026, 11, 9), D(2026, 11, 9))
check("Sun-Thu vs Mon-Fri: Monday works", bool(slots))
team, slots, *_ = run(T + "A,Europe/Berlin,09:00,17:00,Mon-Fri,0,0,yes\nB,Europe/Paris,09:00,17:00,Mon-Fri,0,0,no\n", D(2026, 11, 2), D(2026, 11, 2),
blocked_text="name,date,start,end,reason\nB,2026-11-02,,,holiday\n")
check("optional person blocked all day: slots still found, B missing", slots and all(s["missing"] == ["B"] for s in slots))
check("blocked reason shown", slots and "holiday" in slots[0]["per"]["B"]["reason"])
team, slots, *_ = run(T + "A,Europe/Berlin,09:00,17:00,Mon-Fri,0,0,yes\nB,Europe/Paris,09:00,17:00,Mon-Fri,0,0,yes\n", D(2026, 11, 2), D(2026, 11, 2),
blocked_text="name,date,start,end,reason\nB,2026-11-02,10:00,12:00,dentist\n")
check("required person blocked 10-12 local: no slot overlaps 09:00-11:00 UTC", slots and not any(dt.time(8, 30) < s["utc"].time() < dt.time(11, 0) for s in slots))
team, slots, *_ = run(T + "N,Europe/Berlin,22:00,06:00,Mon-Fri,0,0,yes\n", D(2026, 11, 3), D(2026, 11, 3))
hours = sorted({s["utc"].hour for s in slots})
check("overnight shift 22:00-06:00 Berlin (UTC+1): starts 00:00-04:00 and 21:00-23:00 UTC", hours == [0, 1, 2, 3, 4, 21, 22, 23])
w = []
load_zone("EST", "X", w)
check("abbreviation zone gives a warning", w and "abbreviation" in w[0])
try:
load_zone("Mars/Olympus", "X", [])
ok = False
except InputError as e:
ok = "unknown time zone" in str(e)
check("unknown zone is an input error", ok)
try:
parse_hm("9am", "x")
ok = False
except InputError:
ok = True
check("bad time is an input error", ok)
check("day ranges wrap: Fri-Mon", parse_days("Fri-Mon") == {4, 5, 6, 0})
team3 = T + "A,America/Los_Angeles,09:00,17:00,Mon-Fri,2,0,yes\nB,Europe/Istanbul,09:00,18:00,Mon-Fri,0,2,yes\n"
team, slots, chosen, cum, *_ = run(team3, D(2026, 11, 2), D(2026, 11, 6), series=4, every="day")
st = {k: sum(1 for s in chosen if s["per"][k]["status"] == "flex") for k in ("A", "B")}
check("series of 4 on 4 different dates", len(chosen) == 4 and len({s["utc"].date() for s in chosen}) == 4)
check("rotation shares the stretch: both A and B stretch at least once", st["A"] >= 1 and st["B"] >= 1)
check("rotation pain is balanced (difference <= 2 points)", abs(cum["A"] - cum["B"]) <= 2)
team, slots, chosen, cum, *_ = run(team3, D(2026, 10, 26), D(2026, 11, 20), series=4)
check("weekly series: one meeting in each of 4 ISO weeks", len({s["utc"].isocalendar()[1] for s in chosen}) == 4)
team, slots, *_ = run(T + "A,Europe/Berlin,09:00,17:00,Mon-Fri,0,0,yes\n", D(2026, 11, 2), D(2026, 11, 6), only_days={1, 3})
check("--days Tue,Thu filters candidate days", slots and {s["utc"].weekday() for s in slots} == {1, 3})
team, slots, ch, cum, changes, w, rz = run(T + "A,Europe/Berlin,09:00,17:00,Mon-Fri,0,0,yes\n", D(2026, 11, 2), D(2026, 11, 2))
text = report(team, slots, {"start": "2026-11-02", "end": "2026-11-02", "duration": 60, "top": 3}, rz, w, changes)
check("report renders table", "| 1 | Mon 2026-11-02 08:00 |" in text and "Daylight saving" in text)
j = to_json(team, slots, None, None, changes, w, rz, 3)
check("json output has best slots", len(j["best"]) == 3 and j["best"][0]["start_utc"] == "2026-11-02T08:00Z")
print(f"{passed}/{total} passed")
return 0 if passed == total else 1
def main(argv=None):
ap = argparse.ArgumentParser(description="Find fair meeting slots across time zones")
ap.add_argument("--team")
ap.add_argument("--blocked")
ap.add_argument("--start")
ap.add_argument("--end")
ap.add_argument("--duration", type=int, default=60)
ap.add_argument("--step", type=int, default=30)
ap.add_argument("--days", help="only these weekdays in --ref-zone, e.g. Tue,Wed,Thu")
ap.add_argument("--ref-zone", default="UTC")
ap.add_argument("--top", type=int, default=10)
ap.add_argument("--series", type=int, default=0, help="pick N meetings with rotating inconvenience")
ap.add_argument("--every", default="week", choices=["week", "day"], help="series spacing: one meeting per ISO week (default) or per day")
ap.add_argument("--json", action="store_true")
ap.add_argument("--self-test", action="store_true")
a = ap.parse_args(argv)
if a.self_test:
return self_test()
if not (a.team and a.start and a.end):
ap.print_usage(sys.stderr)
print("error: --team, --start and --end are required", file=sys.stderr)
return 2
try:
start, end = dt.date.fromisoformat(a.start), dt.date.fromisoformat(a.end)
team_text = open(a.team, encoding="utf-8").read()
blocked_text = open(a.blocked, encoding="utf-8").read() if a.blocked else None
only = parse_days(a.days) if a.days else None
team, slots, chosen, cum, changes, warnings, rz = run(team_text, start, end, a.duration, a.step, blocked_text, a.ref_zone, a.top, a.series, only, a.every)
except (InputError, OSError, ValueError) as e:
print(f"error: {e}", file=sys.stderr)
return 2
if a.json:
print(json.dumps(to_json(team, slots, chosen, cum, changes, warnings, rz, a.top), indent=2))
else:
print(report(team, slots, {"start": a.start, "end": a.end, "duration": a.duration, "top": a.top}, rz, warnings, changes, chosen, cum))
return 0 if slots else 1
if __name__ == "__main__":
sys.exit(main())
Ukiyo-e woodblock print on beige paper: a long wooden ferry crossing a calm river in autumn rain, three passengers under red, indigo, and ochre paper umbrellas, a straw-hatted ferryman poling at the stern, a red maple tree upper left, a misty grey-blue mountain behind, and fine diagonal rain lines over everything.
A Japanese ukiyo-e woodblock print of a small wooden ferry boat crossing a wide, calm river in autumn rain, in a wide landscape 16:9 composition on warm beige paper with visible fibers and wood grain texture. A long, low wooden boat sits in the center right of the frame, carrying three seated passengers under round oiled paper umbrellas, from left to right one vermilion red, one deep indigo blue, and one ochre yellow, the passengers wearing simple robes in indigo, ochre, and rust. At the stern on the right, a ferryman stands in a pale blue-grey robe and a wide conical straw hat, pushing a long wooden pole diagonally into the water. In the upper left, a red maple tree reaches into the frame with clusters of bright orange-red leaves, above a grassy, rocky near bank with tall reeds in the lower left. In the background, a misty grey-blue volcano-shaped mountain rises behind a hazy far shore with soft tree silhouettes on the right. Fine diagonal rain lines fall across the whole scene, the river shows gentle horizontal ripple lines, and the sky has a soft bokashi gradient from dark slate grey at the top to pale beige near the horizon. Flat color areas, fine black outlines, muted indigo, ochre, vermilion, and grey palette, quiet and contemplative mood. No text, no seals, no signature, no border.

Create a realistic smartphone travel-vlog portrait set on a lively Tokyo street at dusk. Designed for natural skin texture, candid composition, and an authentic front-camera look. Tested with GPT Image 2.5 Flare on SeeGen AI.
Create a photorealistic smartphone travel-vlog image of a fictional 20-year-old Japanese woman walking through a lively Tokyo side street in the early evening. She has shoulder-length black hair with soft natural bangs, warm brown eyes, realistic skin texture, and a friendly, relaxed expression. She wears a light blue denim jacket over a simple white top, a dark pleated skirt, and a small cream-colored crossbody bag. She holds a clear cup of iced matcha in one hand while filming herself with the other hand at arm's length. Use a wide-angle front-camera perspective with subtle smartphone lens distortion and a spontaneous, candid composition. The street is lined with small restaurants and local shops. Pedestrians walk naturally in the background. Warm shop lights and neon signs begin to glow beneath a cool evening sky. Natural body proportions, realistic hands, sharp eyes, balanced skin tones, documentary travel photography, no beauty filter, no readable brand logos, no watermark, 16:9 aspect ratio.

Japanese maki-e lacquer panel for autumn moon viewing: two white mother-of-pearl rabbits among silver pampas grass under a large gold-powder moon on deep black urushi, with bush clover, falling maple leaves, scattered gold flakes, and a flowing gold-dust stream line.
A wide Japanese maki-e lacquer panel showing two white rabbits sitting among silver pampas grass under a large full autumn moon. The background is deep glossy black urushi lacquer with a mirror-like depth. The moon is a big disc of soft gold powder with a slightly mottled surface, placed in the upper right. The rabbits are built from raised takamaki relief in pearly white and inlaid mother-of-pearl with a faint rainbow shimmer, one looking up at the moon and one nibbling the grass. Long arching pampas plumes sweep across the lower half in fine sprinkled silver and pale gold, mixed with a few bush clover stems with tiny red-lacquer flowers and two or three falling maple leaves in red gold. A scattering of nashiji gold flakes glitters across the lower black ground like dew, and a thin flowing stream line of gold dust curves along the bottom edge. Fine hairline brush detail, delicate gradations from dense to sparse gold, a museum photograph of a polished lacquer box lid lit by soft studio light with a subtle reflection. Quiet, elegant, autumn moon-viewing mood. Wide landscape 16:9. No text, no calligraphy, no signatures, no seals, no logos.
Build an image-ready design brief for a lakeside pottery studio with a wood-fired kiln: shore orientation, compact form with kiln shed and dock, materials palette, wheel-room layout, kiln safety notes, fixed visual details for consistent images, and two prompt seeds (golden-hour exterior and blue-hour workbench).
Act as an architectural concept designer who specializes in small craft studios beside water. Help me build a clear, image-ready design brief for a lakeside pottery studio with a wood-fired kiln. First ask me, in one short list, for: the lake setting (forest shore, rocky cove, open meadow), clay and firing style (stoneware, earthenware, wood-fired, electric assist), studio vibe (rustic cedar, modern glass-and-timber, Japanese-inspired), footprint budget (modest shed, mid-size workshop, generous), and any must-haves (dock, glaze sink, drying racks, guest seating, overnight loft). Then produce the brief with these sections: 1. **Concept in One Sentence**: the feeling and purpose of the studio. 2. **Site and Orientation**: where it sits on the shore, which way the big windows face for light and lake view, kiln shed placement for smoke and wind, path from parking or path to the dock. 3. **Form and Massing**: footprint, roof shape, open bay doors for the wheel room, and a separate or attached kiln shed, with rough dimensions. 4. **Materials and Palette**: exterior cladding (for example weathered cedar), roofing, window frames, dock boards, and interior wood and plaster tones. 5. **Interior Layout**: potter's wheels by the lake-facing windows, wedging table, glaze bench, drying shelves, sink, wood stove if needed, and storage for clay and tools. 6. **Kiln and Safety Notes**: wood-fired kiln orientation, ash and smoke path, safe clearances, and how the shed opens for loading. 7. **Fixed Visual Details**: a numbered list of 8 to 10 details that must stay identical in every image of this studio (cladding, roof color, dock shape, kiln chimney, window count, tree types, water color, golden-hour light direction). 8. **Image Prompt Seeds**: two short prompt starters, one for a golden-hour exterior with dock and kiln shed, and one for a blue-hour interior workbench looking out to the water. Each must restate the fixed visual details and put the key subject in the first sentence. Keep it concise, practical, and buildable. Avoid naming real architects or brands. Flag anything unsafe for wood firing near trees or a dock.
Counts syllables per line with a transparent heuristic, checks common forms (haiku, limerick, iambic pentameter targets), maps end-rhyme schemes (AABB, ABAB, ABCB), and flags near-misses with suggested edits. Use when a user asks "does this scan?", "is this a haiku?", or "what is my rhyme scheme?". Includes a tested stdlib Python checker.
---
name: poetry-meter-and-rhyme-checker
description: Counts syllables per line with a transparent heuristic, checks common forms (haiku, limerick, iambic pentameter targets), maps end-rhyme schemes (AABB, ABAB, ABCB), and flags near-misses with suggested edits. Use when a user asks "does this scan?", "is this a haiku?", or "what is my rhyme scheme?". Includes a tested stdlib Python checker.
---
# Poetry Meter and Rhyme Checker
You help writers see how a draft scans: syllables per line, a plausible stress sketch for English meter targets, and the end-rhyme scheme. You are honest that English syllable counting is heuristic, you show your work, and you suggest small edits instead of rewriting the poem unless asked.
## Files in this skill
- `scripts/poetry_check.py` - syllable estimates, form checks, rhyme-scheme detection (Python 3 standard library only)
- `references/forms-and-targets.md` - syllable and rhyme targets for common short forms
- `references/syllable-heuristic.md` - how the counter works and where it fails (names, -ed, diphthongs)
- `templates/poetry-report.md` - the report shape to return
- `examples/example-haiku-and-quatrain.md` - worked examples
## Workflow
### 1. Collect the facts
- The poem text (keep the user's line breaks).
- Target form if any: haiku, tanka, limerick, sonnet couplet, free verse with a rhyme check only, or custom syllable pattern.
- Dialect notes (US/UK spelling) when relevant to endings like `-our` / `-or`.
### 2. Run the checker
```bash
python3 scripts/poetry_check.py poem.txt
python3 scripts/poetry_check.py poem.txt --form haiku
python3 scripts/poetry_check.py poem.txt --form limerick --rhyme
python3 scripts/poetry_check.py - --json < poem.txt
```
### 3. Advise
1. Show a per-line syllable table and the detected rhyme scheme.
2. Say whether the form target passed, and which lines miss by how many syllables.
3. Offer minimal edits (swap a synonym, split a compound, drop a filler word) rather than a full rewrite.
4. Deliver with `templates/poetry-report.md`.
## Rules
- Always label syllable counts as estimates.
- Do not mock the writer's voice; keep suggestions optional.
- For free verse, still report syllables and rhyme if useful, without forcing a form.
FILE:references/forms-and-targets.md
# Forms and targets
| Form | Syllable target (lines) | Typical rhyme |
|---|---|---|
| Haiku (English teaching form) | 5 / 7 / 5 | usually unrhymed |
| Tanka | 5 / 7 / 5 / 7 / 7 | usually unrhymed |
| Limerick | ~8–9 / 8–9 / 5–6 / 5–6 / 8–9 | AABBA |
| Quatrain (ballad) | often 8 / 6 / 8 / 6 | ABCB or ABAB |
| Heroic couplet | ~10 / 10 (iambic pentameter feel) | AA |
Exact classical Japanese mora counts differ from English syllable teaching forms; this skill uses the common English classroom targets unless the user asks for mora-aware analysis.
FILE:references/syllable-heuristic.md
# Syllable heuristic (honest limits)
The script estimates English syllables by:
1. Lowercasing and stripping punctuation.
2. Counting vowel groups (`a e i o u y`) with common silent-`e` and `-ed` / `-es` adjustments.
3. Treating hyphenated compounds as the sum of parts.
## Known failure modes
- Proper names (`Olivia`, `Michael`) and loanwords.
- Words where `y` is consonantal (`beyond`) vs vocalic (`rhythm` is still hard).
- `-ism`, `-tion`, and compressed pronunciations (`family` as 2 or 3).
When a count looks wrong, say so and offer a manual override in the report.
FILE:templates/poetry-report.md
# Poetry meter and rhyme report
## Target form
- …
## Per-line table
| # | Line | Syllables (est.) | End word | Rhyme letter |
|---|---|---|---|---|
## Form check
- Pass / fail: …
- Misses: …
## Rhyme scheme
- …
## Minimal edit ideas
- …
## Notes on uncertain counts
- …
FILE:examples/example-haiku-and-quatrain.md
# Examples
## Haiku (should pass 5-7-5)
```
An old silent pond
A frog jumps into the pond—
Splash! Silence again.
```
Estimated syllables often land near 5 / 7 / 5 depending on `silent` and `silence`.
## Quatrain rhyme ABCB
```
The woods are lovely, dark and deep,
But I have promises to keep,
And miles to go before I sleep,
And miles to go before I sleep.
```
End words deep/keep/sleep/sleep → AAAA if all rhyme together; a true ABCB sample should use different B and C words.
FILE:scripts/poetry_check.py
#!/usr/bin/env python3
"""Estimate syllables, check simple forms, and map end-rhyme schemes.
Usage:
python3 poetry_check.py poem.txt
python3 poetry_check.py poem.txt --form haiku
python3 poetry_check.py poem.txt --form limerick --rhyme
python3 poetry_check.py - --json < poem.txt
"""
from __future__ import annotations
import argparse
import json
import re
import sys
from pathlib import Path
FORMS = {
"haiku": [5, 7, 5],
"tanka": [5, 7, 5, 7, 7],
"limerick": None, # soft ranges handled separately
}
VOWELS = set("aeiouy")
def strip_word(w: str) -> str:
return re.sub(r"[^a-zA-Z']", "", w).lower()
def syllables_word(word: str) -> int:
w = strip_word(word)
if not w:
return 0
# common overrides
overrides = {
"poem": 2, "poems": 2, "fire": 1, "hour": 1, "our": 1, "//": 0,
"family": 3, "every": 3, "different": 3, "interesting": 4,
"rhythm": 2, "business": 2, "wednesday": 2, "beautiful": 3,
}
if w in overrides:
return overrides[w]
if "-" in word:
return sum(syllables_word(p) for p in word.split("-"))
# remove trailing silent e
base = w
if base.endswith("e") and not base.endswith(("le", "ue", "oe")) and len(base) > 2:
base = base[:-1]
# -ed endings: walked=1 extra often silent
if re.search(r"[^aeiou]ed$", w) and not w.endswith(("ted", "ded")):
base = re.sub(r"ed$", "", w)
if base.endswith("e"):
base = base[:-1]
groups = re.findall(r"[aeiouy]+", base)
count = len(groups) if groups else 1
# adjust ion/ial
if w.endswith(("tion", "sion", "cial", "tial")):
count = max(count, 2)
return max(1, count)
def end_word(line: str) -> str:
words = [w for w in re.findall(r"[A-Za-z']+", line)]
return words[-1].lower() if words else ""
def rhyme_key(word: str) -> str:
w = strip_word(word)
if not w:
return ""
aliases = {
"you": "oo", "blue": "oo", "too": "oo", "two": "oo", "to": "oo", "through": "oo",
"threw": "oo", "shoe": "oo", "who": "oo", "new": "oo", "knew": "oo", "true": "oo",
"lee": "ee", "tea": "ee", "glee": "ee", "sea": "ee", "me": "ee", "we": "ee", "be": "ee",
"green": "een", "keen": "een", "seen": "een", "mean": "een",
}
if w in aliases:
return aliases[w]
matches = list(re.finditer(r"[aeiouy]+", w))
if not matches:
return w
start = matches[-1].start()
if len(matches) >= 2 and len(w) - start < 2:
start = matches[-2].start()
tail = w[start:]
# light normalization for common English end-rhymes
for a, b in (
("igh", "i"), ("ea", "ee"), ("ee", "ee"), ("ey", "ee"), ("ie", "ee"),
("ay", "ei"), ("ai", "ei"), ("ou", "ow"), ("oo", "u"), ("ue", "u"),
):
if a in tail:
tail = tail.replace(a, b)
return tail
def rhyme_scheme(end_words: list[str]) -> str:
mapping = {}
letters = []
next_ord = 0
for w in end_words:
key = rhyme_key(w)
if not key:
letters.append("-")
continue
# near-rhyme: same key
if key not in mapping:
# also merge if share last 2 chars and vowel
found = None
for k, let in mapping.items():
if k == key or (len(k) >= 2 and len(key) >= 2 and k[-2:] == key[-2:]):
found = let
mapping[key] = let
break
if found is None:
let = chr(ord("A") + next_ord)
next_ord += 1
mapping[key] = let
letters.append(mapping[key])
return "".join(letters)
def limerick_ok(counts: list[int]) -> tuple[bool, str]:
if len(counts) != 5:
return False, f"expected 5 lines, got {len(counts)}"
ranges = [(7, 10), (7, 10), (4, 7), (4, 7), (7, 10)]
misses = []
for i, (c, (lo, hi)) in enumerate(zip(counts, ranges), 1):
if not (lo <= c <= hi):
misses.append(f"line {i}: {c} not in {lo}-{hi}")
return (not misses), ("; ".join(misses) if misses else "ok")
def analyze(text: str, form: str | None) -> dict:
lines = [ln.rstrip() for ln in text.splitlines() if ln.strip()]
rows = []
counts = []
ends = []
for i, ln in enumerate(lines, 1):
words = re.findall(r"[A-Za-z']+(?:-[A-Za-z']+)*", ln)
sc = sum(syllables_word(w) for w in words)
ew = end_word(ln)
counts.append(sc)
ends.append(ew)
rows.append({"n": i, "line": ln, "syllables": sc, "end": ew})
scheme = rhyme_scheme(ends)
form_result = None
if form == "limerick":
ok, detail = limerick_ok(counts)
rhyme_ok = scheme == "AABBA"
form_result = {"form": form, "pass": ok and rhyme_ok, "detail": detail,
"rhyme_expected": "AABBA", "rhyme_got": scheme}
elif form in FORMS and FORMS[form]:
target = FORMS[form]
if len(counts) != len(target):
form_result = {"form": form, "pass": False,
"detail": f"expected {len(target)} lines, got {len(counts)}",
"target": target, "got": counts}
else:
misses = [f"line {i}: got {g}, want {t}" for i, (g, t) in enumerate(zip(counts, target), 1) if g != t]
form_result = {"form": form, "pass": not misses, "detail": "; ".join(misses) or "ok",
"target": target, "got": counts}
return {"lines": rows, "rhyme_scheme": scheme, "form_check": form_result}
def main(argv: list[str]) -> int:
ap = argparse.ArgumentParser(description=__doc__)
ap.add_argument("path", help="Poem file, or - for stdin")
ap.add_argument("--form", choices=["haiku", "tanka", "limerick"], help="Form to validate")
ap.add_argument("--rhyme", action="store_true", help="Always print rhyme scheme (default on)")
ap.add_argument("--json", action="store_true")
args = ap.parse_args(argv)
text = sys.stdin.read() if args.path == "-" else Path(args.path).read_text(encoding="utf-8")
result = analyze(text, args.form)
if args.json:
json.dump(result, sys.stdout, indent=2)
sys.stdout.write("\n")
else:
print("n | syl | end | line")
for r in result["lines"]:
print(f"{r['n']:<2}| {r['syllables']:<3}| {r['end']:<12}| {r['line']}")
print(f"rhyme scheme: {result['rhyme_scheme']}")
fc = result["form_check"]
if fc:
print(f"form {fc['form']}: {'PASS' if fc['pass'] else 'FAIL'} ({fc['detail']})")
if "rhyme_expected" in fc:
print(f" rhyme expected {fc['rhyme_expected']}, got {fc['rhyme_got']}")
if result["form_check"] and not result["form_check"]["pass"]:
return 1
return 0
if __name__ == "__main__":
sys.exit(main(sys.argv[1:]))Describe the floating cedar teahouse you imagine on a mountain lake, its scale, roof, screens, engawa, lanterns, boats, and mood, and get an architecture concept, a palette, a numbered list of fixed design details, and two image prompts showing the same teahouse from the misty morning shore approach and from inside at lantern dusk, plus a consistency checklist. Step 1 of a three-step workflow.
Act as an architectural concept brief builder for a floating lakeside teahouse. You translate a vague mood into fixed, visual design details that can be reused across multiple image prompts so the same building stays recognizable from different angles and times of day. You are concrete about materials, dimensions, and what must not change. About the teahouse I imagine: - Setting: a quiet mountain lake in early autumn, forested shores, soft fog - Scale and use: intimate, seats 6 to 8 on floor cushions, ceremonial tea for small groups - Structure vibe: Japanese-inspired cedar, not a theme-park copy; quiet, handmade, slightly weathered - Must include: hipped cedar shingle roof, sliding paper shoji, narrow engawa deck, two stone lanterns on the dock, a small tied wooden boat - Must avoid: neon signs, glass curtain walls, people in the frame, readable text - Mood words: hushed, misty, warm wood, contemplative - Preferred views to generate later: morning approach from the shore path; dusk interior looking out across the water Please do the following: 1. Write a 1-paragraph architecture and setting concept for the floating teahouse. 2. Define a color and material palette (wood tones, paper, water, fog, metal accents). 3. List 10 to 14 fixed design details that must stay identical across every image (roof form and bay count, railing, lantern shapes, dock layout, boat position, mountain silhouette cues, etc.). 4. Produce Image Prompt A: photoreal exterior, misty morning, shore/path approach view, 16:9, embedding every fixed detail in the first half of the prompt. 5. Produce Image Prompt B: photoreal interior at lantern dusk looking out to the lake, 16:9, restating every fixed exterior-visible detail so the building still matches without a reference image. 6. Add a short consistency checklist a human can use when comparing A and B. 7. Add practical notes (what fal flux ultra tends to drop if buried late; keep key objects in the first sentence; under ~200 words per image prompt). Rules: - No people, no readable text, no logos. - Prefer specific measurable details over adjectives alone. - If I left a detail vague, choose one clear option and mark it as your choice. - Output in clear Markdown sections.

A photoreal studio shot of a round cloisonné enamel dish: two white and black cranes flying over a deep blue mountain lake, fine gold wire cells filled with saturated enamel, floral rim border, glossy kiln finish, on dark linen with soft side light.
A close studio photograph of a round cloisonné enamel dish centered in a 16:9 frame on dark charcoal linen. Key subject first: two Japanese-style cranes with white bodies, black necks, and red crowns flying left to right above a deep cobalt mountain lake, every shape outlined in thin raised gold wire cells filled with glossy enamel. Behind the birds, layered indigo and teal mountains, a pale cream cloud band, and a small island pine in dark green enamel. The dish rim is a continuous border of peony and chrysanthemum motifs in coral, gold, and jade green. Metalwork details: tiny gold wire walls catching highlights, slight enamel meniscus inside each cell, a glassy kiln-fired surface with soft specular reflections, copper showing faintly at the outer foot ring. Soft side light from the left, gentle contact shadow on the linen, shallow depth of field with the cranes sharpest. Photoreal product photo of handmade enamelware, saturated true enamel colors, calm museum-craft mood. Not a painting of enamel: a real photographed object. No text, no hallmark letters, no watermark, no hands.

A traditional Edo-style ukiyo-e woodblock print of villagers flying colorful carp and crane kites on a windy hill, with wind-bent pines, a wooden bridge, rice terraces, and a stylized mountain under a soft gradient sky.
A traditional Japanese ukiyo-e woodblock print of a spring kite festival on a windy grassy hill above a river valley. Dozens of rectangular and diamond-shaped kites fill a pale sky that fades from soft cream to light blue, painted with bold carp, crane, and wave motifs in indigo, vermilion, and ochre. In the foreground, a group of villagers in patterned kimono and straw hats strain against long taut kite lines, one child running with a small red kite, an old man laughing as his hat blows away. Wind-bent pine trees lean to one side, and stylized swirling lines show the gusts. In the middle ground, a curved wooden bridge crosses the river, and terraced rice fields and a distant temple roof sit beneath a gently stylized mountain with a flat-topped peak. Flat areas of color, crisp black key-block outlines, subtle bokashi color gradients in the sky and river, visible washi paper texture and slight wood-grain registration marks. Composition in the spirit of Edo-period landscape series, calm and joyful mood. No modern objects, no readable text, no seal or signature, vertical 3:4 composition.

Moody cyberpunk night scene with neon reflections and koi.
Rainy Tokyo alley at night, neon signs in Japanese reflected in a shallow koi pond built into the street, orange and teal neon, wet asphalt, umbrellas, gentle rain streaks, cinematic still, shallow depth of field, ultra-detailed reflections, moody atmosphere

Generates a vertical 9:16 aesthetic photo collage featuring exactly three clearly separated, equal horizontal panels. The same adult Japanese woman with consistent facial features appears in each: a winking close-up selfie on top, a confident over-the-shoulder glance in the middle, and an intimate close-up with hair covering one eye and a subtle pout at the bottom. Captures a cohesive, nostalgic digital-camera vibe with distinct panel borders.
Create a vertical 9:16 collage with exactly 3 clearly separated equal panels stacked vertically. The same adult Japanese woman appears in all three panels with identical facial features and identity. TOP PANEL: close-up selfie, one eye winking. MIDDLE PANEL: over-the-shoulder pose, body turned away, looking back directly at the camera, long hair flowing naturally. BOTTOM PANEL: close-up near the lens, hair covering one eye, cute subtle pout.
bond
The Dynamic Macro Master Prompt (V7.1) Execution Instruction: Before answering, use your search tool to find the "Current Daily Yields" for US Treasuries (2Y, 10Y, 30Y) and Japan Government Bonds (2Y, 10Y, 30Y). Populate the tables below with these live values before beginning the analysis. Role: Senior Cross-Asset Portfolio Strategist. Task: Synthesize live yield data to determine global "Risk On/Off" posture and identify potential volatility triggers. Section 1: Live Core Data Inputs Table A: US vs. Japan Multi-Tenor Snapshot 1-Month TrendTenorUS Treasury (UST)Japan (JGB)Spread (UST - JGB)[Assess 🟢🟡🔴]2-Yearsearch_resultsearch_resultcalculate[Assess 🟢🟡🔴]10-Yearsearch_resultsearch_resultcalculate[Assess 🟢🟡🔴]30-Yearsearch_resultsearch_resultcalculate Table B: US 10Y-2Y Spread Matrix 1-Month TrendMetricCurrent ValueRegime Signal[Assess 🟢🟡🔴]US 10Y-2Y Spreadsearch_resultidentify_regimeSection 2: Analysis Framework US Spread Analysis: Evaluate the current 10Y-2Y spread. Is the curve steepening or flattening? Contrast this with the 2% AI-led GDP expansion vs. the Middle East energy blockade. The "Yen Carry" Pressure Test: Analyze the 10Y UST-JGB spread. If it is narrowing toward 175 bps, calculate the risk of a "Yen Snap" causing a liquidation of global risk assets. Repatriation Risk: Analyze the 30Y spread. Does the current JGB 30Y yield provide enough incentive for Japanese "whales" to sell USTs and bring capital home? Risk On/Off Synthesis: Define the "Net Signal." Section 3: Output Requirements Risk-Off Probability Score: (1–10). Tactical Asset Forecast: BTC/USD, Nasdaq 100, and USD/JPY. The "Sentinel" Play: One growth-focused position and one protective hedge.


Transform an uploaded image into a highly detailed black and white seinen manga illustration, preserving the original subject's identity and facial likeness with precision. The prompt focuses on maintaining the exact features and characteristics while applying a master-level manga art style.
1Transform the uploaded image into an ultra-detailed black and white seinen manga masterpiece while preserving the original subject with absolute accuracy.23ABSOLUTE PRIORITY:...+110 more lines

A digital art prompt for creating a serene autumn lakeside scene. The illustration features a lone fisherman on a rocky shore, surrounded by vibrant autumn trees reflecting in a tranquil lake. The composition balances the fisherman on the left with the colorful trees on the right, evoking a peaceful and contemplative mood in a minimalist style.
1{2 "colors": {3 "color_temperature": "warm",...+79 more lines

1{2 "prompt": "You will perform an image edit using the person from the provided photo as the main subject. The face must remain clear and unaltered. Transform the subject into a contemplative **Zen Monk/Gardener**, meticulously raking patterns in a pristine Japanese Zen garden at dawn. Emphasize minimalist aesthetics, soft natural light, tranquil colors, and a profound sense of peace and mindfulness.",3 "details": {...+14 more lines
Ghibli style anime character of male
A cozy hand-drawn anime-style male character inspired by soft nostalgic Japanese animation. He has warm brown eyes, gentle smile, shoulder-length slightly wavy dark hair, wearing a soft beige cardigan over a light pastel dress. He is sitting at a wooden desk with a notebook labeled “Savings Plan” and a small cup of tea beside her. Warm golden sunset lighting coming through the window, soft shadows, detailed background, peaceful atmosphere, cinematic framing, highly detailed, 4k illustration, wholesome, calm mood.

Creating a serene digital illustration depicting a peaceful, moonlit street scene by the water, featuring a warmly lit cafe and a black cat on a balcony. This prompt is ideal for generating stylized atmospheric illustrations with a focus on emotional and tranquil urban night settings.
1{2 "colors": {3 "color_temperature": "cool",...+73 more lines

Ancient Japanese village at night, quiet and empty, deeply spiritual atmosphere. Traditional wooden houses lining a narrow stone street, wet from recent rain, reflecting soft warm paper lantern light. Low mist drifting slowly through the village, moving with intention, as if guided by an unseen presence. Paper lanterns glowing gently one by one, with no visible source of ignition. At the end of the street, an old moss-covered torii gate emerging from the fog. Behind it, a subtle sacred presence — no physical form, no face — only a soft, breathing glow within the mist, calm and ancient, watching without judgment, like a shintō kami. An old tree beside the path wrapped with a weathered shimenawa rope. Shide paper streamers moving slightly despite the still air. Footsteps visible on the wet stone ground, leading forward like a quiet ritual path. Mood of reverence, silence, and timelessness. The boundary between the visible world and the unseen feels thin and sacred. Cinematic composition with strong leading lines and deep perspective. Volumetric fog, soft natural light diffusion. Color palette of deep indigo blues, muted forest greens, and warm amber highlights. Photorealistic cinematic realism, ultra-detailed organic textures, natural imperfections, subtle asymmetry, atmospheric concept art, high resolution, 8K quality. Negative prompt: anime, cartoon, illustration, horror, aggressive mood, monsters, demons, jump scare, modern buildings, neon lights, cyberpunk, city elements, text, watermark, logo, characters in foreground, sharp artificial lighting, oversaturated colors

This prompt guides you to create a minimalist digital illustration inspired by Ryo Takemasa. The illustration features a vast, surreal landscape with vibrant red and orange bushes, a winding white path, and a lone figure. It emphasizes themes of exploration and solitude, using a clean, graphic style with high contrast and vibrant colors.
1{2 "colors": {3 "color_temperature": "warm",...+75 more lines
Que actue como profesor de japones empezando desde 0 para aprender la gramatica japonesa, cada dia 1 hora y con rencompensas, ejercicios, repaso...
Act as a Japanese language tutor. Your task is to provide daily structured lessons for learning Japanese. You will: - Offer daily lessons focusing on different aspects such as vocabulary, grammar, and conversation. - Include quizzes and exercises to reinforce learning. - Ensure lessons are suitable for beginners. Variables: - beginner - Level of difficulty - topic - Specific lesson topic
I want you to act as a Japanese Kanji quiz machine. Each time I ask you for the next question, you are to provide one random Japanese kanji from JLPT N5 kanji list and ask for its meaning. You will generate four options, one correct, three wrong. The options will be labeled from A to D. I will reply to you with one letter, corresponding to one of these labels. You will evaluate my each answer based on your last question and tell me if I chose the right option. If I chose the right label, you will congratulate me. Otherwise you will tell me the right answer. Then you will ask me the next question.
You've reached the end