Apparently, this latte art looks like male genitalia, and the Internet thinks that's hilarious.
"looks really good! the shading is nice, and you even got the foam dissipating into the coffee! i won't point out what's already been pointed out a thousand times, though…"
{"collectionMetadata":{"baseUrl":"https://s3-us-west-2.amazonaws.com/levi-portfolio-media","thumbnailName":"thumbnail.png","thumbnailDimensions":{"width":128,"height":128},"logoName":"logo.png"},"posts":[{"id":"about-levi","titleShort":"About
Levi\n(and other links)","titleLong":"About
Levi","emphasis":1,"color":"#bc8e62","urls":{"devlog":"https://devlog.levi.dev","githubProfile":"https://github.com/levilindsey","facebook":"https://facebook.com/levislindsey","twitter":"https://twitter.com/levisl","linkedin":"https://linkedin.com/in/levi-lindsey","youtube":"https://www.youtube.com/playlist?list=PLIuJN99AFOPSF3p4f0siFo22XiMXqijQU","soundcloud":"https://soundcloud.com/levilindsey","itchio":"https://levilindsey.itch.io/","snoring-cat":"https://snoringcat.games","resume":"https://levi.dev/resume"},"jobTitle":"Gameplay
Engineer","location":"Seattle,
WA","date":{"start":"4/27/1988","end":"Present","tieBreaker":100},"categories":[],"images":[{"fileName":"levi-and-kid.jpg","description":"levi
with his
daughter."},{"fileName":"levi-in-savitri.jpg","description":"Levi
playing
Satyavan in the opera \"Savitri\" by Gustav Holst. In this scene,
Satyavan is warning off
whomever is lurking in the
forest."},{"fileName":"jackie-and-levi-in-maui.jpg","description":"Levi
with his wife,
Jackie, in
Maui."},{"fileName":"roydor-commission-levi-solo-480.png","description":"A
pixel-art avatar a friend commissioned for
Levi."},{"fileName":"levi-at-forge.jpg","description":"Levi designed
and built a
four-burner, propane-powered forge for his
father."},{"fileName":"levi-in-the-bartered-bride.jpg","description":"Levi
playing
Vašek in the opera \"The Bartered Bride\" by Bedřich Smetana.
In this scene,
Vašek, a stuttering fool, is musing about about his forthcoming
arranged
marriage."},{"fileName":"jackie-and-levi-wedding-toast.jpg","description":"Levi
and Jackie
at their
wedding."},{"fileName":"levi-at-camp-hahobas.jpg","description":"Levi
leading a
campfire song about peeling a banana. He was a counselor and Life
Guard at Camp Hahobas, a
Boy Scout summer
camp."},{"fileName":"levi-head-shot.jpg","description":"Levi at the
University of Washington's Friday Harbor Laboratories on San Juan
Island."}],"videos":[],"content":"_\"I write code. I sing songs. I
create
things.\"_\r\n\r\n## The Bio\r\n\r\nLevi is a Gameplay Engineer. He
used to be a Frontend
(Web) Software Engineer. He's also constantly tinkering on game-dev
side
projects—which are all highlighted in this
portfolio.\r\n\r\nLevi is originally from
Olympia, WA. He was in California for a bit, and he now lives in
Seattle, WA with his wife
Jackie and their daughter.\r\n\r\nOutside the realm of computer
science, Levi has many
hobbies and interests. First and foremost, he is a musician. Levi is a
classically trained
singer and has led in many operas and musicals; some of his more
notable performances
include: [Dido and Aeneas][dido-and-aeneas-url] (Aeneas),
[Savitri][savitri-url]
(Satyavan), and [My Fair Lady][my-fair-lady-url] (Henry Higgins). Levi
also [sings with a
capella groups][love-like-you-url] and [plays a lot of
ukulele][down-today-url]. Check out
some of his [recordings on YouTube][youtube-url]!\r\n\r\nSome of his
other hobbies
include: board games/card games, laser-cutting, brewing beer,
blacksmithing, scuba diving,
gardening, baking, and a never-ending list of home
improvements.\r\n\r\n## The
Cover-Letter Schpiel\r\n\r\nLevi is a seasoned technical leader with
experience guiding
projects through all stages of development and across a wide array of
platforms.\r\n\r\n-
He invents novel interactive experiences.\r\n- He develops with an
emphasis on
maintainable and self-documented code.\r\n- He designs maintainable
solutions to
high-level problems, in ambiguous problem spaces, with complicated
dependencies.\r\n- He
leads teams, designs technical roadmaps, and coordinates timelines and
dependencies.\r\n-
He advocates open-source technology. You can fork all of his many
side-projects at
[github.com/levilindsey](https://github.com/levilindsey)!
\r\n\r\n\r\n[github-url]:
https://github.com/levilindsey\r\n[google-url]:
https://google.com/about\r\n[gcp-url]:
https://cloud.google.com\r\n[jackie-url]:
http://www.jackieandlevi.com/jackie\r\n[dido-and-aeneas-url]:
https://en.wikipedia.org/wiki/Dido_and_Aeneas\r\n[savitri-url]:
https://en.wikipedia.org/wiki/Savitri_(opera)\r\n[my-fair-lady-url]:
https://en.wikipedia.org/wiki/My_Fair_Lady\r\n[youtube-url]:
https://www.youtube.com/playlist?list=PLIuJN99AFOPSF3p4f0siFo22XiMXqijQU\r\n[love-like-you-url]:
https://www.youtube.com/watch?v=yH7L_bZSwbM&list=PLIuJN99AFOPSF3p4f0siFo22XiMXqijQU\r\n[down-today-url]:
https://youtu.be/HmALRuBoDno\r\n[camp-hahobas-url]:
https://web.archive.org/web/20160807121041/http://www.hahobas.org/\r\n"},{"id":"manticore","titleShort":"Manticore\nGames","titleLong":"Manticore
Games","emphasis":1,"color":"#ffb116","urls":{"homepage":"https://www.manticoregames.com/"},"jobTitle":"Senior
Software Engineer -
Gameplay","location":"Remote","date":{"start":"4/2023","end":"Present","tieBreaker":30},"categories":["Work","C++","Unreal","Game","3D","Teamwork"],"images":[],"videos":[],"content":"_[Manticore
Games](https://www.manticoregames.com/) is a video game company based
in San Mateo,
California._\r\n\r\nLevi is a Senior Software Engineer working on
gameplay.\r\n"},{"id":"devlog","titleShort":"Devlog","titleLong":"Devlog","emphasis":0.9,"color":"#ffe642","urls":{"devlog":"https://devlog.levi.dev"},"jobTitle":"","location":"","date":{"start":"1/2021","end":"Present","tieBreaker":18},"categories":["AI","Art","Animation","Music","Godot","Game","2D","Solo-Work"],"images":[],"videos":[],"content":"Levi
originally used this devlog to publish weekly updates on his progress
during his
year-and-a-half-long game-dev sabbatical.\r\n\r\nHe now uses it for
less-frequent updates
on recent game jams and his overall career.\r\n\r\n- During his
sabbatical Levi published
more than 1.5 posts per week.\r\n- His devlog has received more than
26,000 views (as of
January 2023).\r\n- His devlog includes more than 17 deep-dive and
tutorial posts
([levi.dev/game-dev-tutorials](levi.dev/game-dev-tutorials)).\r\n - In
particular, a
6-part tutorial series on creating platformer AIs
([levi.dev/platformer-ai-tutorial](https://levi.dev/platformer-ai-tutorial)).
\r\n"},{"id":"surfacer","titleShort":"Platformer\nprocedural\npathfinding","titleLong":"Surfacer:
A procedural pathfinding 2D-platformer framework for
Godot","emphasis":1,"color":"#4488c0","urls":{"demo":"https://snoringcat.games/play/squirrel-away","github":"https://github.com/SnoringCatGames/surfacer","godot-asset-library":"https://godotengine.org/asset-library/asset/968"},"jobTitle":"","location":"","date":{"start":"2/2019","end":"Present","tieBreaker":15},"categories":["Side-Project","App","Godot","Game","AI","2D","Library"],"images":[{"fileName":"surfaces-and-edges.png","description":"The
Surfacer framework works pre-parsing a level into a \"platform
graph\". The nodes are
represented by points along the different surfaces in the level
(floors, walls, and
ceilings). The edges are represented by possible movement trajectories
between points
along
surfaces."},{"fileName":"navigator-preselection.png","description":"A*
search is
used to find paths through the platform
graph."},{"fileName":"edge-step-calculation-debugging.png","description":"Surfacer
includes a powerful platform graph inspector, which makes it easy to
understand and debug
how the platform graph was
calculated."}],"videos":[{"videoHost":"youtube","id":"2Q15fjAEncg","description":"A
demonstration of the Surfacer framework in action. A cat is controlled
by mouse clicks to
navigate through a level of 2D
platforms."}],"content":"_Point-and-click
platformers!_\r\n\r\n_An AI and pathfinding 2D-platformer framework
for
[Godot](https://godotengine.org/)._\r\n\r\n_\"Surfacer\": Like a
platformer, but with
walking, climbing, and jumping on all surfaces!_\r\n\r\n\r\n\r\n**tl;dr**:
Surfacer works by **pre-parsing** a level into a **\"platform
graph\"**. The **nodes** are
represented by points along the different surfaces in the level
(floors, walls, and
ceilings). The **edges** are represented by possible movement
trajectories between points
along surfaces. There are different types of edges for different types
of movement (e.g.,
jumping from a floor to a floor, falling from a wall, walking along a
floor). At run time,
**[A* search](https://en.wikipedia.org/wiki/A*_search_algorithm)** is
used to calculate a
path to a given destination.\r\n\r\nSome features include:\r\n-
Surfacer includes a
powerful **character-behavior system** for easily creating a character
AI with high-level
behaviors like \"wander\", \"follow\", \"run-away\", \"return\".\r\n-
Easy-to-use
point-and-click navigation for player-controlled characters.\r\n-
[Configurable movement
parameters](https://github.com/SnoringCatGames/surfacer/blob/master/src/platform_graph/edge/models/movement_params.gd)
on a per-character basis (e.g., horizontal acceleration, jump power,
gravity, collision
boundary shape and size, which types of edge movement are
allowed).\r\n- Level creation
using Godot's standard pattern with a [TileMap in the 2D scene
editor](https://docs.godotengine.org/en/3.2/tutorials/2d/using_tilemaps.html).\r\n-
Preparsing the level into a platform graph, and using A* search for
efficient path-finding
at runtime.\r\n- A powerful inspector for analyzing the platform
graph, in order to debug
and better understand how edges were calculated.\r\n- Walking on
floors, climbing on
walls, climbing on ceilings, jumping and falling from anywhere.\r\n-
[Variable-height jump
and
fast-fall](https://kotaku.com/the-mechanics-behind-satisfying-2d-jumping-1761940693).\r\n-
Adjusting movement trajectories to move around intermediate surfaces
(such as jumping over
a wall or around a floor).\r\n\r\nSee [more details in the library's
README](https://github.com/SnoringCatGames/surfacer).\r\n\r\nYou can
also read more about
how Surfacer's AI and movement works in **[this series of devlog posts
on
devlog.levi.dev](https://devlog.levi.dev/2021/09/building-platformer-ai-from-low-level.html)**.\r\n\r\n>
_Surfacer is owned by [Snoring Cat
LLC](https://snoringcat.games)._"},{"id":"scaffolder","titleShort":"Godot\napplication\nscaffolding","titleLong":"Scaffolder:
Application scaffolding and utility functionality for
Godot","emphasis":1,"color":"#4488c0","urls":{"github":"https://github.com/SnoringCatGames/scaffolder","godot-asset-library":"https://godotengine.org/asset-library/asset/969"},"jobTitle":"","location":"","date":{"start":"11/2020","end":"Present","tieBreaker":12},"categories":["Side-Project","App","Godot","Game","2D","Library"],"images":[{"fileName":"scaffolder-gui.gif","description":"Scaffolder
provides a bunch of general-purpose UI and application scaffolding,
such as a widget
library and a a screen layout and navigation
system."},{"fileName":"scaffolder-resizing.gif","description":"Scaffolder
provides a
sophisticated rescaling system to help you make responsive
UIs."}],"videos":[],"content":"This is an opinionated framework that
provides a bunch of
general-purpose application scaffolding and utility functionality for
Godot
games.\r\n\r\n## Features\r\n\r\n### Viewport scaling\r\n\r\nThis
framework handles
viewport scaling directly. You will need to turn off Godot's built-in
viewport scaling
(`Display > Window > Stretch > Mode = disabled`).\r\n\r\nThis provides
some powerful
benefits over Godot's standard behaviors, but requires you to be
careful with how you
define your GUI layouts.\r\n\r\n#### Handling camera zoom\r\n\r\nThis
provides limited
flexibility in how far the camera is zoomed. That is, you will be able
to see more of the
level on a larger screen, but not too much more of the level.
Similarly, on a wider
screen, you will be able to able to see more from side to side, but
not too much
more.\r\n\r\n- You can configure a minimum and maximum aspect ratio
for the game
region.\r\n- You can configure a default screen size and aspect ratio
that the levels are
designed around.\r\n- At runtime, if the current viewport aspect ratio
is greater than the
max or less than the min, bars will be shown along the sides or top
and bottom of the game
area.\r\n- At runtime, the camera zoom will be adjusted so that the
same amount of level
is showing, either vertically or horizontally, as would be visible
with the configured
default screen size. If the screen aspect ratio is different than the
default, then a
little more of the level is visible in the other direction.\r\n- Any
annotations that are
drawn in the separate annotations CanvasLayer are automatically
transformed to match
whatever the game-area's current zoom and position is.\r\n- Click
positions can also be
transformed to match the game area.\r\n\r\n#### Handling GUI
scale\r\n\r\n- At runtime, a
`gui_scale` value is calculated according to how the current screen
resolution compares to
the expected default screen resolution, as described above.\r\n- Then
all fonts—which are
registered with the scaffold configuration—are resized according to
this `gui_scale`.\r\n-
Then the size, position, and scale of all GUI nodes are updated
accordingly.\r\n\r\n####
Constraints for how you define your GUI layouts\r\n\r\n> TODO: List
any other
constraints/tips.\r\n\r\n- Avoid custom positions, except maybe for
centering images. For
example:\r\n - Instead of encoding a margin/offset, use a
VBoxContainer or HBoxContainer
parent, and include an empty spacer sibling with size or min-size.\r\n
- This is
especially important when your positioning is calculated to include
bottom/right-side
margins.\r\n- Centering images:\r\n - To center an image, I often
place a `TextureRect`
inside of a `Control` inside of some time of auto-positioning
container.\r\n - I then set
the image position in this way: `TextureRect.rect_position =
-TextureRect.rect_size/2`.\r\n - This wrapper pattern also works well
when I need to scale
the image.\r\n- In general, whenever possible, I find it helpful to
use a VBoxContainer or
HBoxContainer as a parent, and to have children use the shrink-center
size flag for both
horizontal and vertical directions along with a min-size.\r\n\r\n###
Analytics\r\n\r\nThis
feature depends on the proprietary third-party **[Google
Analytics](https://analytics.google.com/analytics/web/#/)**
service.\r\n\r\n- Fortunately,
Google Analytics is at least free to use.\r\n- To get started with
Google Analytics, [read
this
doc](https://support.google.com/analytics/answer/1008015?hl=en).\r\n-
To learn more
about the \"Measurement Protocol\" API that this class uses to send
event info, [read this
doc](https://developers.google.com/analytics/devguides/collection/protocol/v1).\r\n-
To
learn more about the \"Reporting API\" you could use to run arbitrary
queries on your
recorded analytics, [read this
doc](https://developers.google.com/analytics/devguides/reporting/core/v4).\r\n
-
Alternatively, you could just use [Google's convenient web
client](http://analytics.google.com/).\r\n\r\n#### \"Privacy Policy\"
and \"Terms and
Conditions\" documents\r\n\r\nIf you intend to record any sort of user
data (including
app-usage analytics or crash logs), you should create a \"Privacy
Policy\" document and a
\"Terms and Conditions\" document. These are often legally required
when recording any
sort of app-usage data. Fortunately, there are a lot of tools out
there to help you easily
generate these documents. You could then easily host these as
view-only [Google
Docs](https://docs.google.com/).\r\n\r\nHere are two such generator
tools that might be
useful, and at least have free-trial options:\r\n- [Termly's privacy
policy
generator](https://termly.io/products/privacy-policy-generator/?ftseo)\r\n-
[Nishant's
terms and conditions
generator](https://app-privacy-policy-generator.nisrulz.com/)\r\n\r\n>
_**DISCLAIMER:**
I'm not a lawyer, so don't interpret anything from this framework as
legal advice, and
make sure you understand which laws you need to obey._\r\n\r\n###
Automatic error/crash
reporting\r\n\r\nThis feature currently depends on the proprietary
third-party **[Google
Cloud Storage](https://cloud.google.com/storage)** service. But you
could easily override
it to upload logs somewhere else.\r\n\r\n### Screen layout and
navigation\r\n\r\n- You can
control transitions through `Gs.nav`.\r\n- It is easy to include
custom screens and
exclude default screens.\r\n- Here are some of the default screns
included:\r\n - Main
menu\r\n - Credits\r\n - Settings\r\n - Configurable to display
checkboxes, dropdowns, or
plain text for whatever settings you might want to support.\r\n -
Level select\r\n -
Game/level\r\n - Pause\r\n - Notification\r\n - Configurable to
display custom text and
buttons as needed.\r\n - Game over\r\n\r\n### Lots of useful utility
functions\r\n\r\nIt
might just be easiest to scroll through some of the following files to
see what sorts of
functions are included:\r\n-
[`Audio`](https://github.com/SnoringCatGames/scaffolder/blob/master/src/utils/Audio.gd)\r\n-
[`CameraShake`](https://github.com/SnoringCatGames/scaffolder/blob/master/src/utils/CameraShake.gd)\r\n-
[`DrawUtils`](https://github.com/SnoringCatGames/scaffolder/blob/master/src/utils/DrawUtils.gd)\r\n-
[`Geometry`](https://github.com/SnoringCatGames/scaffolder/blob/master/src/utils/Geometry.gd)\r\n-
[`Profiler`](https://github.com/SnoringCatGames/scaffolder/blob/master/src/utils/Profiler.gd)\r\n-
[`SaveState`](https://github.com/SnoringCatGames/scaffolder/blob/master/src/data/SaveState.gd)\r\n-
[`Time`](https://github.com/SnoringCatGames/scaffolder/blob/master/src/utils/Time.gd)\r\n-
[`Utils`](https://github.com/SnoringCatGames/scaffolder/blob/master/src/utils/Utils.gd)\r\n\r\n###
A widget library\r\n\r\nFor example:\r\n-
[`AccordionPanel`](https://github.com/SnoringCatGames/scaffolder/blob/master/src/gui/AccordionPanel.gd)\r\n-
[`LabeledControlList`](https://github.com/SnoringCatGames/scaffolder/blob/master/src/gui/labeled_control_list/LabeledControlList.gd)\r\n-
[`ShinyButton`](https://github.com/SnoringCatGames/scaffolder/blob/master/src/gui/ShinyButton.gd)\r\n-
[`NavBar`](https://github.com/SnoringCatGames/scaffolder/blob/master/src/gui/NavBar.gd)\r\n\r\n>
_Scaffolder is owned by [Snoring Cat
LLC](https://snoringcat.games)._\r\n"},{"id":"snoring-cat","titleShort":"Snoring
Cat
LLC","titleLong":"Snoring Cat
LLC","emphasis":0.6,"color":"#7e664d","urls":{"snoring-cat":"https://snoringcat.games"},"jobTitle":"Owner
and manager","location":"Seattle,
WA","date":{"start":"2/2021","end":"Present","tieBreaker":9},"categories":["Work","Art","Animation","Music","Godot","Game","2D","Solo-Work"],"images":[{"fileName":"icon-512.png","description":"A
pixel-art sleeping cat."}],"videos":[],"content":"Levi formed Snoring
Cat LLC to publish
some of his more substantial games and software projects
under.\r\n\r\nCheck out Snoring
Cat LLC's site at
[snoringcat.games](https://snoringcat.games).\r\n\r\nIf you're curious
about what-all went into forming this LLC, check out [this devlog
post](https://devlog.levi.dev/2021/02/snoring-cat-forming-llc.html).\r\n"},{"id":"Music","titleShort":"Music:\nPerformances
&\ncompositions","titleLong":"Music composition and
performance","emphasis":0.6,"color":"#f774ff","urls":{"youtube":"https://www.youtube.com/playlist?list=PLIuJN99AFOPRwoYLk6O_j8kPK6UtWQTIk","soundcloud":"https://soundcloud.com/levilindsey"},"jobTitle":"Singer,
arranger,
composer","location":"","date":{"start":"4/27/1988","end":"Present","tieBreaker":3},"categories":["Music"],"images":[],"videos":[],"content":"Levi
has an extensive musical background.\r\n\r\n* He has been a singer all
his life, and he's
played [various
instruments](https://www.youtube.com/playlist?list=PLIuJN99AFOPTzVmY-g6RAwP9CAIIa-PtS)
along the way.\r\n* He has a Bachelor of Music in Vocal Performance
from the University of
Washington.\r\n* He's sung in many operas and musicals, including
**Dido and Aeneas**
(Aeneas), **Savitri** (Satyavan), and **My Fair Lady** (Henry
Higgins).\r\n* He's sung in
dozens of [choirs and a capella
groups](https://www.youtube.com/playlist?list=PLIuJN99AFOPRl5MH9GwFQWpPEP3zkPLBs).\r\n*
In
recent years, he's also been [composing
music](https://soundcloud.com/levilindsey/sets/chiptunes) (mostly
chiptunes for his game
projects).\r\n\r\nYou can listen to many of Levi's
[compositions](https://soundcloud.com/levilindsey/sets/chiptunes) and
[performances](https://youtube.com/playlist?list=PLIuJN99AFOPSF3p4f0siFo22XiMXqijQU)
on
YouTube and SoundCloud.\r\n\r\n \r\n