Memoji character (11 expressions) on the engine's motion; Claude limit shows time to reset; ChatGPT weekly limit from Codex logs
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -444,56 +444,15 @@ private func drawMochi(_ ctx: CGContext, p: GreetPose) {
|
||||
ctx.rotate(by: CGFloat(p.tilt))
|
||||
ctx.scaleBy(x: CGFloat(p.sx), y: CGFloat(p.sy))
|
||||
|
||||
drawHandL(ctx, hw: hw, hh: hh, p: p)
|
||||
drawHandR(ctx, hw: hw, hh: hh, p: p)
|
||||
|
||||
let mpath = mochiPath(hw: hw, hh: hh)
|
||||
whiteFill(ctx, mpath, x0: hw*0.6, y0: -hh, x1: -hw*0.6, y1: hh)
|
||||
|
||||
if p.tint > 0 {
|
||||
let cs = CGColorSpaceCreateDeviceRGB()
|
||||
let c0 = CGColor(red: 127/255, green: 180/255, blue: 234/255, alpha: CGFloat(p.tint))
|
||||
let c1 = CGColor(red: 127/255, green: 180/255, blue: 234/255, alpha: 0)
|
||||
if let g = CGGradient(colorsSpace: cs, colors: [c0,c1] as CFArray, locations: [0,1]) {
|
||||
ctx.saveGState()
|
||||
ctx.addPath(mpath); ctx.clip()
|
||||
ctx.drawLinearGradient(g, start: CGPoint(x: 0, y: hh),
|
||||
end: CGPoint(x: 0, y: -hh*0.1), options: [])
|
||||
ctx.restoreGState()
|
||||
}
|
||||
}
|
||||
|
||||
ctx.saveGState()
|
||||
ctx.addPath(mpath); ctx.clip()
|
||||
ctx.setFillColor(gHex("#16171A"))
|
||||
ctx.setStrokeColor(gHex("#16171A"))
|
||||
let er = CGFloat(p.hb*0.06)
|
||||
let sp = CGFloat(p.hb*0.19)
|
||||
let lx = CGFloat(p.lookX)*hw*0.42
|
||||
let ly = CGFloat(p.lookY)*hh*0.28 + hh*0.12 + CGFloat(p.eyeRoll)*hh*1.25
|
||||
for sd: CGFloat in [-1, 1] {
|
||||
ctx.saveGState()
|
||||
ctx.translateBy(x: sd*sp+lx, y: ly)
|
||||
if p.eye == .happy {
|
||||
ctx.setLineWidth(er*0.95); ctx.setLineCap(.round)
|
||||
ctx.beginPath()
|
||||
ctx.addArc(center: CGPoint(x: 0, y: er*0.6), radius: er*1.25,
|
||||
startAngle: .pi*1.15, endAngle: .pi*1.85, clockwise: false)
|
||||
ctx.strokePath()
|
||||
} else if p.eye == .content {
|
||||
ctx.setLineWidth(er*0.95); ctx.setLineCap(.round)
|
||||
ctx.beginPath()
|
||||
ctx.addArc(center: CGPoint(x: 0, y: -er*0.5), radius: er*1.25,
|
||||
startAngle: .pi*0.15, endAngle: .pi*0.85, clockwise: false)
|
||||
ctx.strokePath()
|
||||
} else {
|
||||
ctx.scaleBy(x: 1, y: max(0.12, CGFloat(p.open)))
|
||||
ctx.addEllipse(in: CGRect(x: -er, y: -er, width: er*2, height: er*2))
|
||||
ctx.fillPath()
|
||||
}
|
||||
ctx.restoreGState()
|
||||
}
|
||||
ctx.restoreGState()
|
||||
// BroV: the Memoji replaces the drawn body, eyes and hands.
|
||||
let face: MemojiExpression = {
|
||||
if p.eye == .happy || p.eye == .content { return .happy }
|
||||
if p.open < 0.35 { return .blink }
|
||||
if p.open < 0.8 { return .halfblink }
|
||||
return .neutral
|
||||
}()
|
||||
MemojiCG.draw(face, in: ctx, center: CGPoint(x: CGFloat(p.lookX) * hw * 0.12, y: 0),
|
||||
side: hh * 2 * 1.45)
|
||||
|
||||
// Activity badge
|
||||
if p.badge > 0.01 {
|
||||
|
||||
Reference in New Issue
Block a user